PageSourceSearch

https://gohiocommute.com/js/app.js

js gohiocommute.com collected 2026-09-28 11:33:54 UTC 352,049 bytes, 8,741 lines download raw bytes

1var __assign = (this && this.__assign) || function () {
2    __assign = Object.assign || function(t) {
3        for (var s, i = 1, n = arguments.length; i < n; i++) {
4            s = arguments[i];
5            for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
6                t[p] = s[p];
7        }
8        return t;
9    };
10    return __assign.apply(this, arguments);
11};
12var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
13    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
14    return new (P || (P = Promise))(function (resolve, reject) {
15        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
16        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
17        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
18        step((generator = generator.apply(thisArg, _arguments || [])).next());
19    });
20};
21var __generator = (this && this.__generator) || function (thisArg, body) {
22    var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
23    return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
24    function verb(n) { return function (v) { return step([n, v]); }; }
25    function step(op) {
26        if (f) throw new TypeError("Generator is already executing.");
27        while (g && (g = 0, op[0] && (_ = 0)), _) try {
28            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;
29            if (y = 0, t) op = [op[0] & 2, t.value];
30            switch (op[0]) {
31                case 0: case 1: t = op; break;
32                case 4: _.label++; return { value: op[1], done: false };
33                case 5: _.label++; y = op[1]; op = [0]; continue;
34                case 7: op = _.ops.pop(); _.trys.pop(); continue;
35                default:
36                    if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
37                    if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
38                    if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
39                    if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
40                    if (t[2]) _.ops.pop();
41                    _.trys.pop(); continue;
42            }
43            op = body.call(thisArg, _);
44        } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
45        if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
46    }
47};
48var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
49    if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
50        if (ar || !(i in from)) {
51            if (!ar) ar = Array.prototype.slice.call(from, 0, i);
52            ar[i] = from[i];
53        }
54    }
55    return to.concat(ar || Array.prototype.slice.call(from));
56};
57if (!!navigator.userAgent.match(/IEMobile/i))
58    Modernizr.addTest('iemobile', function () {
59        return !!navigator.userAgent.match(/IEMobile/i);
60    });
61if (/MSIE 10\.0.*Touch(?!.*IEMobile)/i.test(navigator.userAgent))
62    Modernizr.addTest('ie10touch', function () {
63        return /MSIE 10\.0.*Touch(?!.*IEMobile)/i.test(navigator.userAgent);
64    });
65if (/MSIE 6\.0(?!.*IEMobile)/i.test(navigator.userAgent))
66    Modernizr.addTest('ie6', function () {
67        return /MSIE 6\.0(?!.*IEMobile)/i.test(navigator.userAgent);
68    });
69if (/MSIE 7\.0(?!.*IEMobile)/i.test(navigator.userAgent))
70    Modernizr.addTest('ie7', function () {
71        return /MSIE 7\.0(?!.*IEMobile)/i.test(navigator.userAgent);
72    });
73if (/MSIE 8\.0(?!.*IEMobile)/i.test(navigator.userAgent))
74    Modernizr.addTest('ie8', function () {
75        return /MSIE 8\.0(?!.*IEMobile)/i.test(navigator.userAgent);
76    });
77if (/MSIE 9\.0(?!.*IEMobile)/i.test(navigator.userAgent))
78    Modernizr.addTest('ie9', function () {
79        return /MSIE 9\.0(?!.*IEMobile)/i.test(navigator.userAgent);
80    });
81if (!!navigator.userAgent.match(/MSIE 10/i))
82    Modernizr.addTest('ie10', function () {
83        return !!navigator.userAgent.match(/MSIE 10/i);
84    });
85if (/(?:\sTrident\/7\.0;.*\srv:11\.0)/i.test(navigator.userAgent) ||
86    /MSIE 11/i.test(navigator.userAgent))
87    Modernizr.addTest('ie11', function () {
88        return (/(?:\sTrident\/7\.0;.*\srv:11\.0)/i.test(navigator.userAgent) ||
89            /MSIE 11/i.test(navigator.userAgent));
90    });
91angular.module('templates', []);
92var appModules = [
93    'ui.router',
94    'vtmo',
95    'VTMOService',
96    'ui.select2',
97    'ngTouch',
98    'ngTable',
99    'ngTableExport',
100    'ngSocial',
101    'ngAnimate',
102    'ngCsv',
103    'angulartics',
104    'angulartics.google.analytics',
105    'angularFileUpload',
106    'ui.sortable',
107    'ui.utils',
108    'ui.bootstrap',
109    'matchmedia-ng',
110    'fayzaan.gRecaptcha.v3',
111    'ngMessages',
112    'feature.tools',
113    'feature.modals',
114    'feature.surveys',
115    'feature.schoolpools',
116    'feature.proxyAsUser',
117    'feature.programTemplates',
118    'feature.locations',
119    'feature.rideshares',
120    'feature.challenges',
121    'feature.challengeTeams',
122    'countTo',
123    'feature.networkadmin',
124    'feature.maps',
125    'feature.markdown',
126    'feature.formvalidation',
127    'feature.formElements',
128    'feature.events',
129    'feature.usualmode',
130    'feature.accessibility',
131    'templates',
132    'feature.incentives',
133    'feature.calendar',
134    'feature.triplogs',
135    'feature.smartTripLogs',
136    'feature.loginPopup',
137    'feature.referenceCapture',
138    'feature.postRegistrationCapture',
139    'feature.promptAstroDownload',
140    'feature.requiredInformationCapture',
141    'feature.postRegistrationCarpool',
142    'feature.extraMapContent',
143    'feature.tripsDashboardWidget',
144    'feature.enhancedReporting',
145    'feature.registration',
146    'feature.integrations',
147    'feature.accountactivation',
148    'feature.partnerAPI',
149    'feature.quicklog',
150    'feature.subsites',
151    'feature.digital-inventory',
152    'feature.vanpoolManagement',
153    'feature.carpoolPassManagement',
154    'feature.pages',
155    'feature.emails',
156    'feature.emailTemplates',
157    'feature.rideboard',
158    'feature.myCommuteWidget',
159    'feature.smartTripCommunication',
160    'feature.hotjar',
161    'feature.carpoolManagementModule',
162    'features.specializedProviders',
163    'features.achievements',
164    'features.premium',
165    'feature.combinedLedgers',
166    'feature.PrimaryNetwork',
167    'feature.fulfillmentIntegrations',
168    'feature.assetManagement',
169    'wu.masonry',
170    'angularUtils.directives.dirPagination',
171    'pasvaz.bindonce',
172    'multipleDatePicker',
173    'kendo.directives',
174    'angularMoment',
175    'appFilters',
176    'appDirectives',
177    'appServices',
178    'appComponents',
179    'customerModule',
180    'feature.requests',
181    'feature.vehicleManagement',
182    'feature.parkingManagement',
183    'feature.parkingPermitManagement',
184    'feature.parkingActivityManagement',
185    'feature.parkingSessionManagement',
186    'feature.parkingInfractionManagement',
187    'feature.parkingFacilityManagement',
188    'feature.poolManagement',
189];
190var app = angular.module('vtmoFront', appModules);
191app.config(function ($logProvider, $compileProvider, $animateProvider, $httpProvider) {
192    var debugEnabled = (window.debugEnabled = JSON
193        ? JSON.parse(window.CONFIG.debugLoggingEnabled)
194        : window.CONFIG.debugLoggingEnabled === true);
195    $logProvider.debugEnabled(debugEnabled);
196    if (!debugEnabled)
197        $compileProvider.debugInfoEnabled(false);
198    $animateProvider.classNameFilter(/animated/);
199    $httpProvider.useApplyAsync(true);
200    if (window.location.href.indexOf('-develop') === -1 &&
201        window.CONFIG.defaultGA4Id) {
202        gtag('config', window.CONFIG.defaultGA4Id, {
203            groups: 'default',
204        });
205    }
206    if (window.CONFIG.googleAnalytics && window.CONFIG.googleAnalytics.length) {
207        window.CONFIG.googleAnalytics.forEach(function (trackerObj, idx) {
208            if (trackerObj.trackerGA4Id && trackerObj.trackerGA4Id.length) {
209                var trackerName = (trackerObj.trackerName ||
210                    (trackerObj.trackerDomain || window.CONFIG.siteKeyword) + idx).replace(/\W+/g, '');
211                gtag('config', trackerObj.trackerGA4Id, {
212                    groups: trackerName,
213                });
214            }
215        });
216        var ga4Ids = __spreadArray([
217            window.CONFIG.defaultGA4Id
218        ], window.CONFIG.googleAnalytics.map(function (t) { return t.trackerGA4Id; }), true).filter(Boolean);
219        ga4Ids.forEach(function (measurementId) {
220            gtag('config', measurementId, {
221                link_attribution: {
222                    cookie_name: '_glid',
223                    cookie_expires: 63072000,
224                },
225            });
226            gtag('config', measurementId, {
227                allow_google_signals: true,
228            });
229        });
230    }
231});
232var vError = {
233    SESSION_REQUIRED: 'sessionRequired',
234    USER_SESSION_REQUIRED: 'userSessionRequired',
235    ADMIN_SESSION_REQUIRED: 'adminSessionRequired',
236};
237app.value('vError', vError);
238app.value('CONFIG', window.CONFIG);
239app.value('moment', window.moment || null);
240app.value('L', window.L || null);
241app.value('_', window._ || null);
242app.value('kendo', window.kendo || null);
243app.run(function ($rootScope, $state, $location, $stateParams, $http, vSession, vFacebook, $log, $timeout, $window, vError, Dialogs, SessionUserDataService, matchmedia, CONFIG, KendoThemeService) {
244    window.onMobileDevice = $rootScope.onMobileDevice =
245        /Android|webOS|iPhone|iPad|iPod|Nokia|BlackBerry/i.test(navigator.userAgent);
246    $rootScope.Modernizr = window.Modernizr;
247    $rootScope.isEdge = /Edge\/\d+/i.test(navigator.userAgent);
248    window.matchmedia = $rootScope.matchmedia = matchmedia;
249    $rootScope._ = window._;
250    $rootScope.moment = window.moment;
251    $log = $log.getInstance('app.run');
252    $log.debug('App Initialized');
253    $rootScope.CONFIG = window.CONFIG;
254    $log.debug('CONFIG LOADED', window.CONFIG);
255    $timeout(function () {
256        document.title = CONFIG.siteTitle;
257    }, 1500);
258    $rootScope.sessionData = SessionUserDataService;
259    $rootScope.devScope = false;
260    $rootScope.$state = $state;
261    $rootScope.$stateParams = $stateParams;
262    $rootScope.EMAIL_REGEXP =
263        /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
264    $rootScope.ZIP_REGEXP = /^\d{5}(?:[-\s]\d{4})?$/;
265    $rootScope.URL_REGEXP =
266        /[(http(s)?):\/\/(www\.)?a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)/i;
267    $rootScope.globalModalName = 'account.login';
268    $rootScope.globalModalTemplate = '/templates/account/login.html';
269    $rootScope.globalModalVisible = false;
270    if ($rootScope.CONFIG.facebookAppId != null)
271        vFacebook.init($rootScope.CONFIG.facebookAppId);
272    if (window.SESSION_DATA) {
273        vSession.prepareSession(window.SESSION_DATA);
274    }
275    else {
276        vSession.refresh();
277    }
278    if (CONFIG.account.googleOauth.clientId) {
279        var gapiScript = document.createElement('script');
280        gapiScript.type = 'text/javascript';
281        gapiScript.src = 'https://apis.google.com/js/platform.js';
282        gapiScript.onload = function () {
283            gapi.load('auth2', function () {
284                gapi.auth2.init({
285                    client_id: CONFIG.account.googleOauth.clientId,
286                });
287            });
288        };
289        document.body.appendChild(gapiScript);
290    }
291    if (!Object.is) {
292        Object.is = function (x, y) {
293            if (x === y) {
294                return x !== 0 || 1 / x === 1 / y;
295            }
296            else {
297                return x !== x && y !== y;
298            }
299        };
300    }
301    if (!_.isEmpty(CONFIG.observedHolidays.defaults)) {
302        moment.modifyHolidays.set(CONFIG.observedHolidays.defaults);
303    }
304    if (!_.isEmpty(CONFIG.observedHolidays.custom)) {
305        moment.modifyHolidays.add(CONFIG.observedHolidays.custom);
306    }
307    $rootScope.$watch('session.user', function (user) {
308        if (!user && $state.current.name == 'dashboard')
309            $state.go('home');
310        if (user && !$state.current.name && !String(window.location).match('#')) {
311            setTimeout(function () {
312                $state.go(CONFIG.defaultUserLandingState);
313            });
314        }
315    });
316    $location.url(decodeURIComponent($location.url()));
317    $rootScope.$on('$locationChangeStart', function (event, newURL, prevURL) {
318        $log.debug('$locationChangeStart', event, newURL, prevURL);
319        if (newURL.match('astroTriplog=true')) {
320            $rootScope.triplogSource = 'astro';
321        }
322        $location.url(decodeURIComponent($location.url()).replace('astroTriplog=true', ''));
323    });
324    $rootScope.$on('$locationChangeSuccess', function (event, newURL, prevURL) {
325        $log.debug('$locationChangeSuccess', event, newURL, prevURL);
326        $rootScope.fromUrl =
327            (newURL.indexOf('#!m=support') > -1 ? prevURL : newURL) ||
328                $location.absUrl();
329    });
330    $rootScope.$on('$stateChangeStart', function (event, toState, toParams, fromState, fromParams) {
331        $log.debug('\n**** $stateChangeStart ****', '\nevent :: ', event, '\ntoState :: ', toState, '\ntoParams :: ', toParams, '\nfromState :: ', fromState, '\nfromParams :: ', fromParams);
332        if (toState.kendoTheme)
333            KendoThemeService.changeTheme(toState.kendoTheme);
334        else
335            KendoThemeService.resetTheme();
336        $rootScope.defaultTab = toParams.tab;
337    });
338    $rootScope.$on('$stateChangeSuccess', function (event, toState, toParams, fromState, fromParams) {
339        $log.debug('\n**** $stateChangeSuccess ****', '\nevent :: ', event, '\ntoState :: ', toState, '\ntoParams :: ', toParams, '\nfromState :: ', fromState, '\nfromParams :: ', fromParams);
340        if (!session.user && toState.name == 'dashboard.dashboard')
341            $state.go('home');
342        if (CONFIG.localize && Localize) {
343            Localize.translatePage();
344        }
345        if (!!toState.data && toState.data.iframeMap) {
346            $timeout(function () {
347                jQuery('iframe.iframeMap').animate({
348                    height: jQuery(window).height() * 1.2,
349                });
350            }, 10);
351        }
352        if (window.debugEnabled && (toState || {}).name) {
353            $timeout(function () {
354                document.title = CONFIG.siteTitle + ': ' + toState.name;
355            }, 1500);
356        }
357        if (!window.debugEnabled && (toState || {}).title) {
358            $timeout(function () {
359                document.title = CONFIG.siteTitle + ' - ' + toState.title;
360            }, 1500);
361        }
362        if (!window.debugEnabled && !(toState || {}).title) {
363            $timeout(function () {
364                document.title = CONFIG.siteTitle;
365            }, 1500);
366        }
367    });
368    var promptForLogin = function (error, toState, toParams) {
369        $rootScope.pendingState = {
370            state: toState,
371            params: toParams,
372            search: $location.search(),
373        };
374        $timeout(function () {
375            $rootScope.globalModalShow('account.login');
376            var timeoutId;
377            var waitingForSession = $rootScope.$watch('session.user', function (user) {
378                if (user) {
379                    var meetsRequirements = false;
380                    switch (error) {
381                        case vError.USER_SESSION_REQUIRED:
382                            if (user._id)
383                                meetsRequirements = true;
384                            break;
385                        case vError.NETWORK_ADMIN_SESSION_REQUIRED:
386                            if (user._id && (user.isAdmin || user.managedNetworks.length))
387                                meetsRequirements = true;
388                            break;
389                        case vError.ADMIN_SESSION_REQUIRED:
390                            if (user._id && user.isAdmin)
391                                meetsRequirements = true;
392                            break;
393                    }
394                    if (meetsRequirements && $rootScope.pendingState) {
395                        var pendingState = $rootScope.pendingState;
396                        var queryParamStrings = [];
397                        _.forEach(pendingState.search, function (value, key) {
398                            queryParamStrings.push(key + '=' + value);
399                        });
400                        _.apply(pendingState.params, pendingState.search);
401                        var url = $state.href(pendingState.state, pendingState.params);
402                        if (queryParamStrings.length) {
403                            url += '?' + queryParamStrings.join('&');
404                        }
405                        window.location = url;
406                        waitingForSession();
407                        delete $rootScope.pendingState;
408                        clearTimeout(timeoutId);
409                    }
410                }
411            });
412            timeoutId = setTimeout(function () {
413                delete $rootScope.pendingState;
414                waitingForSession();
415            }, 60 * 1000 * 5);
416        });
417    };
418    $rootScope.$on('$stateChangeError', function (event, toState, toParams, fromState, fromParams, error) {
419        $log.debug('\n**** $stateChangeError ****', '\nevent :: ', event, '\ntoState :: ', toState, '\ntoParams :: ', toParams, '\nfromState :: ', fromState, '\nfromParams :: ', fromParams, '\nerror :: ', error);
420        if (toState.name === 'home') {
421            Dialogs.alert({
422                unsafeMessage: "An error occurred while loading the application. Please contact <a href='mailto:[email protected]'>[email protected]</a> if this persists.",
423            });
424            return;
425        }
426        switch (error) {
427            case vError.USER_SESSION_REQUIRED:
428                $state.go('home').then(function () {
429                    promptForLogin(error, toState, toParams);
430                    Dialogs.alert('You must be logged in to access this content.');
431                });
432                break;
433            case vError.NETWORK_ADMIN_SESSION_REQUIRED:
434                $state.go('home').then(function () {
435                    promptForLogin(error, toState, toParams);
436                    Dialogs.alert('You must be logged in as a network manager to access this content.');
437                });
438                break;
439            case vError.ADMIN_SESSION_REQUIRED:
440                $state.go('home').then(function () {
441                    promptForLogin(error, toState, toParams);
442                    Dialogs.alert('You must be logged in as an Admin user in order to access this content.');
443                });
444                break;
445            case vError.SESSION_REQUIRED:
446            default:
447                $state.go('home').then(function () {
448                    Dialogs.alert("We weren't able to locate the content you requested.");
449                });
450        }
451        if (fromState.kendoTheme)
452            KendoThemeService.changeTheme(fromState.kendoTheme);
453        else
454            KendoThemeService.resetTheme();
455    });
456    $rootScope.focusOnElement = function (option) {
457        if (option === void 0) { option = '.view-parent'; }
458        $(option).attr('tabIndex', -1).focus();
459    };
460    $rootScope.focusOnItinerary = function (mode, index) {
461        var itineraryElement = '.' + mode + '-' + index;
462        $(itineraryElement).attr('tabIndex', -1).focus();
463    };
464    var unsubMedia = {};
465    unsubMedia['print'] = matchmedia.onPrint(function (mediaQueryList) {
466        window.isPrint = $rootScope.isPrint = mediaQueryList.matches;
467    }, $rootScope);
468    unsubMedia['screen'] = matchmedia.onScreen(function (mediaQueryList) {
469        window.isScreen = $rootScope.isScreen = mediaQueryList.matches;
470    }, $rootScope);
471    unsubMedia['phone'] = matchmedia.onPhone(function (mediaQueryList) {
472        window.isPhone = $rootScope.isPhone = mediaQueryList.matches;
473    });
474    unsubMedia['tablet'] = matchmedia.onTablet(function (mediaQueryList) {
475        window.isTablet = $rootScope.isTablet = mediaQueryList.matches;
476    });
477    unsubMedia['desktop'] = matchmedia.onDesktop(function (mediaQueryList) {
478        window.isDesktop = $rootScope.isDesktop = mediaQueryList.matches;
479    });
480    unsubMedia['portrait'] = matchmedia.onPortrait(function (mediaQueryList) {
481        window.isPortrait = $rootScope.isPortrait = mediaQueryList.matches;
482    });
483    unsubMedia['landscape'] = matchmedia.onLandscape(function (mediaQueryList) {
484        window.isLandscape = $rootScope.isLandscape = mediaQueryList.matches;
485    });
486    if (Localize)
487        $rootScope.Localize = Localize;
488});
489;
490'use strict';
491var VTMOService = angular.module('VTMOService', ['restangular']);
492VTMOService.provider('sessionSecurity', function Security() {
493    this.require = function (sessionType) {
494        return function (vtmoResolves, $q, $location, vSession, vError) {
495            var sessionFn = vtmoResolves[sessionType + 'Session'];
496            return sessionFn($q, $location, vSession, vError);
497        };
498    };
499    this.requireUser = function () {
500        return this.require('user');
501    };
502    this.requireAdmin = function () {
503        return this.require('adminUser');
504    };
505    this.advancedManager = function () {
506        return this.require('advancedManagerUser');
507    };
508    this.requireNetworkManager = function () {
509        return this.require('networkAdminUser');
510    };
511    this.requireSpecificNetworkManager = function (networkIdParam) {
512        if (!networkIdParam)
513            networkIdParam = 'network';
514        return function (vtmoResolves, $stateParams, $q, $location, vSession, vError) {
515            var networkId = $stateParams[networkIdParam];
516            if (!networkId)
517                $q.reject('networkAdminSessionRequired');
518            return vtmoResolves.specificNetworkAdminSession(networkId, $q, $location, vSession, vError);
519        };
520    };
521    this.$get = function () {
522        return 'Only use this during config stages, doy.';
523    };
524});
525VTMOService.service('vtmoResolves', function ($q, CONFIG, $vhttp) {
526    var vErrors = {
527        SESSION_REQUIRED: 'sessionRequired',
528        USER_SESSION_REQUIRED: 'userSessionRequired',
529        ADMIN_SESSION_REQUIRED: 'adminSessionRequired',
530        NETWORK_ADMIN_SESSION_REQUIRED: 'networkAdminSessionRequired',
531        ADVANCED_MANAGER_SESSION_REQUIRED: 'advancedManagerSessionRequired',
532    };
533    var adminUserSession = function ($q, $location, vSession, vError) {
534        var deferred = $q.defer();
535        if (vSession.token === null) {
536            vSession.refresh().then(function (session) {
537                verifySessionPermission(session);
538            }, function () {
539                deferred.reject(vError.ADMIN_SESSION_REQUIRED);
540            });
541        }
542        else {
543            verifySessionPermission(vSession);
544        }
545        function verifySessionPermission(session) {
546            if (session.user && session.user.isAdmin) {
547                deferred.resolve(session.user);
548            }
549            else {
550                deferred.reject(vError.ADMIN_SESSION_REQUIRED);
551            }
552        }
553        return deferred.promise;
554    };
555    var advancedManagerUserSession = function ($q, $location, vSession, vError) {
556        var deferred = $q.defer();
557        if (vSession.token === null) {
558            vSession.refresh().then(function (session) {
559                verifySessionPermission(session);
560            }, function () {
561                deferred.reject(vError.ADMIN_SESSION_REQUIRED);
562            });
563        }
564        else {
565            verifySessionPermission(vSession);
566        }
567        function verifySessionPermission(session) {
568            var user = _.get(session, 'user');
569            if (user && (user.isAdmin || user.isAdvancedManager))
570                deferred.resolve(true);
571            else if (CONFIG.premiumNetworks.advancedManagementEnabled &&
572                user &&
573                !_.has(user, 'isAdvancedManager') &&
574                user.managedNetworks.length) {
575                $vhttp
576                    .get('/api/v1/ra-connected/is-advanced-manager')
577                    .then(function (isAdvanced) {
578                    isAdvanced
579                        ? deferred.resolve(isAdvanced)
580                        : deferred.reject(vError.ADVANCED_MANAGER_REQUIRED);
581                });
582            }
583            else
584                deferred.reject(vError.ADMIN_SESSION_REQUIRED);
585        }
586        return deferred.promise;
587    };
588    var networkAdminUserSession = function ($q, $location, vSession, vError) {
589        var deferred = $q.defer();
590        if (vSession.token == null) {
591            vSession.refresh().then(function (session) {
592                verifySessionPermission(session);
593            }, function () {
594                deferred.reject(vError.NETWORK_ADMIN_SESSION_REQUIRED);
595            });
596        }
597        else {
598            verifySessionPermission(vSession);
599        }
600        function verifySessionPermission(session) {
601            if (session.user &&
602                (session.user.isAdmin ||
603                    (session.user.managedNetworks && session.user.managedNetworks.length))) {
604                deferred.resolve(session.user);
605            }
606            else {
607                deferred.reject(vError.NETWORK_ADMIN_SESSION_REQUIRED);
608            }
609        }
610        return deferred.promise;
611    };
612    var specificNetworkAdminUserSession = function (networkId, $q, $location, vSession, vError) {
613        var deferred = $q.defer();
614        if (vSession.token == null) {
615            vSession.refresh().then(function (session) {
616                verifySessionPermission(session);
617            }, function () {
618                deferred.reject(vError.NETWORK_ADMIN_SESSION_REQUIRED);
619            });
620        }
621        else {
622            verifySessionPermission(vSession);
623        }
624        function verifySessionPermission(session) {
625            if (session.user &&
626                (session.user.isAdmin ||
627                    _.includes(session.user.managedNetworks, networkId))) {
628                deferred.resolve(session.user);
629            }
630            else {
631                deferred.reject(vError.NETWORK_ADMIN_SESSION_REQUIRED);
632            }
633        }
634        return deferred.promise;
635    };
636    var userSession = function ($q, $location, vSession, vError) {
637        var deferred = $q.defer();
638        if (vSession.token === null) {
639            vSession.refresh().then(function (session) {
640                verifySessionPermission(session);
641            }, function () {
642                deferred.reject(vError.USER_SESSION_REQUIRED);
643            });
644        }
645        else {
646            verifySessionPermission(vSession);
647        }
648        function verifySessionPermission(session) {
649            if (session.user) {
650                deferred.resolve(session.user);
651            }
652            else {
653                deferred.reject(vError.USER_SESSION_REQUIRED);
654            }
655        }
656        return deferred.promise;
657    };
658    var users = function (vUser) {
659        return vUser.getList();
660    };
661    var networks = function (vNetworks) {
662        return vNetworks.getList();
663    };
664    var triplogs = function (vTriplogs) {
665        return vTriplogs.getList();
666    };
667    var tripsearches = function (vTripsearches) {
668        return vTripsearches.getList();
669    };
670    return {
671        adminUserSession: adminUserSession,
672        specificNetworkAdminSession: specificNetworkAdminUserSession,
673        advancedManagerUserSession: advancedManagerUserSession,
674        networkAdminUserSession: networkAdminUserSession,
675        userSession: userSession,
676        users: users,
677        networks: networks,
678        triplogs: triplogs,
679        tripsearches: tripsearches,
680    };
681});
682VTMOService.config(function (RestangularProvider, $provide) {
683    RestangularProvider.setBaseUrl('/api/v1');
684    RestangularProvider.setRestangularFields({
685        id: '_id',
686    });
687    var enhanceLogger = function ($log) {
688        var _$log = (function ($log) {
689            return {
690                log: $log.log,
691                info: $log.info,
692                warn: $log.warn,
693                debug: $log.debug,
694                error: $log.error,
695            };
696        })($log), prepareLogFn = function (logFn, className) {
697            var enhancedLogFn = function () {
698                var args = Array.prototype.slice.call(arguments), now = moment().format('hh:mm:ss.S');
699                var newArgs = [];
700                newArgs.push(now + ' -');
701                if (className && className.length) {
702                    newArgs.push(className);
703                }
704                newArgs = newArgs.concat(args);
705                logFn.apply(null, newArgs);
706            };
707            enhancedLogFn.logs = [];
708            return enhancedLogFn;
709        }, getInstance = function (className) {
710            className = className !== undefined ? className + ' ::' : '';
711            return {
712                log: prepareLogFn(_$log.log, className),
713                info: prepareLogFn(_$log.info, className),
714                warn: prepareLogFn(_$log.warn, className),
715                debug: prepareLogFn(_$log.debug, className),
716                error: prepareLogFn(_$log.error, className),
717            };
718        };
719        $log.log = prepareLogFn($log.log);
720        $log.info = prepareLogFn($log.info);
721        $log.warn = prepareLogFn($log.warn);
722        $log.debug = prepareLogFn($log.debug);
723        $log.error = prepareLogFn($log.error);
724        $log.getInstance = getInstance;
725        return $log;
726    };
727    $provide.decorator('$log', [
728        '$delegate',
729        function ($delegate) {
730            enhanceLogger($delegate);
731            return $delegate;
732        },
733    ]);
734});
735VTMOService.service('vSession', function ($rootScope, $http, $timeout, $q, $log, vUser) {
736    $log = $log.getInstance('vSession');
737    var Session = function () {
738        var session = this;
739        $rootScope.$watch('session.token', function (token) {
740            $log.debug('session.token changed', token);
741            if (token) {
742                $log.debug('Setting Authorization Header', 'Bearer ' + token);
743                $http.defaults.headers.common.Authorization = 'Bearer ' + token;
744            }
745            else {
746                $log.debug('Deleting Authorization Header');
747                delete $http.defaults.headers.common.Authorization;
748            }
749        });
750        $rootScope.$watch('facebook.facebookAccessToken', function (accessToken) {
751            $log.debug('facebook.facebookAccessToken changed', accessToken);
752            if (accessToken && session.user == null) {
753                $rootScope.session.facebookLogin(accessToken);
754            }
755        });
756    };
757    Session.prototype.emptySession = function () {
758        for (var key in this)
759            delete this[key];
760    };
761    Session.prototype.prepareSession = function (sessionData) {
762        $log.debug('prepareSession', sessionData);
763        this.emptySession();
764        angular.extend(this, sessionData);
765        if (this.user != null) {
766            this.user = vUser.getUser(this.user);
767        }
768        return this;
769    };
770    Session.prototype.tokenLogin = function (token) {
771        $log.debug('tokenLogin(token)', token);
772        var deferred = $q.defer();
773        var self = this;
774        $http
775            .get('/api/v1/session', {
776            headers: { Authorization: 'Bearer ' + token },
777        })
778            .success(onSessionSuccess)
779            .error(onSessionFault);
780        function onSessionSuccess(data, status, headers, config) {
781            $log.debug('tokenLogin:RESULT', data);
782            if (data.hasOwnProperty('token')) {
783                var session = self.prepareSession(data);
784                $timeout(function () {
785                    deferred.resolve(session);
786                });
787            }
788            else {
789                deferred.reject(data);
790            }
791        }
792        function onSessionFault(data, status, headers, config) {
793            $log.debug('tokenLogin:ERROR', data);
794            deferred.reject(data);
795        }
796        return deferred.promise;
797    };
798    Session.prototype.emailLogin = function (email, password) {
799        $log.debug('emailLogin(email,password)', email, password);
800        var deferred = $q.defer();
801        var self = this;
802        $http
803            .post('/api/v1/session', { email: email, password: password })
804            .success(function (data, status, headers, config) {
805            $log.debug('emailLogin:RESULT', data);
806            if (data.hasOwnProperty('token')) {
807                var session = self.prepareSession(data);
808                $timeout(function () {
809                    deferred.resolve(session);
810                });
811            }
812            else {
813                deferred.reject(data);
814            }
815        })
816            .error(function (data, status, headers, config) {
817            $log.debug('emailLogin:ERROR', data);
818            deferred.reject(data);
819        });
820        return deferred.promise;
821    };
822    Session.prototype.facebookLogin = function (facebookAccessToken) {
823        $log.debug('facebookLogin(facebookAccessToken)', facebookAccessToken);
824        var deferred = $q.defer();
825        var self = this;
826        $http
827            .post('/api/v1/session', { facebookAccessToken: facebookAccessToken })
828            .success(function (data, status, headers, config) {
829            $log.debug('facebookLogin:RESULT', data);
830            if (data.hasOwnProperty('token')) {
831                var session = self.prepareSession(data);
832                $timeout(function () {
833                    deferred.resolve(session);
834                });
835            }
836            else {
837                deferred.reject(data);
838            }
839        })
840            .error(function (data, status, headers, config) {
841            $log.debug('facebookLogin:ERROR', data);
842            deferred.reject(data);
843        });
844        return deferred.promise;
845    };
846    Session.prototype.refresh = _.debounce(function () {
847        $log.debug('refresh()');
848        var deferred = $q.defer();
849        var self = this;
850        $http
851            .get('/api/v1/session', { data: { xcache: Date.now() } })
852            .success(function (data, status, headers, config) {
853            var session = self.prepareSession(data);
854            deferred.resolve(session);
855        })
856            .error(function (data, status, headers, config) {
857            deferred.reject(data);
858        });
859        return deferred.promise;
860    }, 450);
861    Session.prototype.logout = function () {
862        $log.debug('logout()');
863        var deferred = $q.defer();
864        var self = this;
865        $http['delete']('/api/v1/session')
866            .success(function (data, status, headers, config) {
867            self.user = null;
868            $timeout(function () {
869                self.refresh.call(self);
870            }, 50);
871            deferred.resolve();
872        })
873            .error(function (data, status, headers, config) {
874            deferred.reject(data);
875            self.refresh();
876        });
877        return deferred.promise;
878    };
879    Session.prototype.proxyAsUser = function (userId) {
880        if (!this.user.isAdmin) {
881            throw 'This is not allowed you cod!';
882        }
883        var deferred = $q.defer();
884        var self = this;
885        $http
886            .post('/api/v1/session/proxy-as-user', { userId: userId })
887            .success(function (data, status, headers, config) {
888            self.refresh();
889            deferred.resolve();
890        })
891            .error(function (data, status, headers, config) {
892            console.error('ProxyAsUser Failed', data);
893            deferred.reject(data);
894        });
895        return deferred.promise;
896    };
897    Session.prototype.proxyAsNetworkMember = function (networkId, userId) {
898        if (this.user.isAdmin) {
899            return this.proxyAsUser(userId);
900        }
901        if (!CONFIG.premiumNetworks.proxyAsMemberEnabled ||
902            !this.user.managedNetworks.length) {
903            throw 'Unauthorized: proxy as member';
904        }
905        var deferred = $q.defer();
906        var self = this;
907        $http
908            .post('/api/v1/session/proxy-as-network-member/' + networkId, {
909            userId: userId,
910        })
911            .success(function (data, status, headers, config) {
912            self.refresh();
913            deferred.resolve();
914        })
915            .error(function (data, status, headers, config) {
916            deferred.reject(data);
917        });
918        return deferred.promise;
919    };
920    return (window.session = $rootScope.session = new Session());
921});
922VTMOService.service('SurveyMediator', function (vSession, Dialogs, $state) {
923    function resolve() {
924        var resolveFn = vSession.user.pendingStateResolve();
925        vSession.user.pendingChallenge.joinModel.post().then(function () {
926            vSession.user.pendingChallenge = {};
927            vSession.user.pendingStateResolve = function () { };
928            resolveFn();
929        }, function (error) {
930            vSession.refresh();
931            Dialogs.alert('You were not added to challenge.');
932        });
933    }
934    function pending(survey) {
935        return vSession.user.pendingChallenge && match(survey);
936    }
937    function match(survey) {
938        return vSession.user.pendingChallenge.requiredJoinSurvey == survey;
939    }
940    function register(challenge, team) {
941        Dialogs.confirm({
942            unsafeMessage: '<i><var teamName>' +
943                _.escape(challenge.name) +
944                '</var></i> has a required survey.  Go to survey?',
945            callback: onConfirmResult.bind(null, challenge, team),
946        });
947        function onConfirmResult(challenge, team, confirmed) {
948            if (confirmed) {
949                vSession.user.pendingChallenge = challenge;
950                vSession.user.pendingStateResolve = function () {
951                    return team
952                        ? team
953                        : function () {
954                            var challengeId = challenge._id;
955                            $state.go('challenges.view', { challenge: challengeId });
956                        };
957                };
958                $state.go('survey', { survey: challenge.requiredJoinSurvey });
959            }
960        }
961    }
962    return {
963        register: register,
964        resolve: resolve,
965        match: match,
966        pending: pending,
967    };
968});
969VTMOService.service('vAccountActivation', function ($http, $q, $log, vSession) {
970    $log = $log.getInstance('vAccountActivation');
971    var AccountActivation = function () { };
972    AccountActivation.prototype.requestAccountActivation = function (email) {
973        $log.debug('requestAccountActivation', email);
974        var deferred = $q.defer();
975        var onResult = function (data, status) {
976            $log.debug('requestAccountActivation:RESULT', data);
977            deferred.resolve(data);
978        };
979        var onError = function (data, status) {
980            $log.debug('requestAccountActivation:ERROR', data);
981            deferred.reject(data);
982        };
983        $http
984            .post('/api/v1/activationtoken/', { email: email })
985            .success(onResult)
986            .error(onError);
987        return deferred.promise;
988    };
989    AccountActivation.prototype.validateActivationToken = function (token) {
990        var deferred = $q.defer();
991        var onResult = function (data, status) {
992            if (data.valid == true) {
993                deferred.resolve(data);
994            }
995            else {
996                deferred.reject(data);
997            }
998        };
999        var onError = function (data, status) {
1000            deferred.reject(data);
1001        };
1002        $http
1003            .get('/api/v1/activationtoken/' + token)
1004            .success(onResult)
1005            .error(onError);
1006        return deferred.promise;
1007    };
1008    AccountActivation.prototype.activateAccount = function (token, password) {
1009        var deferred = $q.defer();
1010        var onResult = function (data, status) {
1011            vSession.refresh();
1012            deferred.resolve(data);
1013        };
1014        var onError = function (data, status) {
1015            deferred.reject(data);
1016        };
1017        $http
1018            .post('/api/v1/activationtoken/' + token, {})
1019            .success(onResult)
1020            .error(onError);
1021        return deferred.promise;
1022    };
1023    return (window.vAccountActivation = new AccountActivation());
1024});
1025VTMOService.service('vPasswordReset', function ($http, $q, $log, vSession) {
1026    $log = $log.getInstance('vPasswordReset');
1027    var PasswordReset = function () { };
1028    PasswordReset.prototype.requestPasswordReset = function (email) {
1029        $log.debug('requestPasswordReset', email);
1030        var deferred = $q.defer();
1031        var onResult = function (data, status) {
1032            $log.debug('requestPasswordReset:RESULT', data);
1033            deferred.resolve(data);
1034        };
1035        var onError = function (data, status) {
1036            $log.debug('requestPasswordReset:ERROR', data);
1037            deferred.reject(data);
1038        };
1039        $http
1040            .post('/api/v1/passwordreset/', { email: email })
1041            .success(onResult)
1042            .error(onError);
1043        return deferred.promise;
1044    };
1045    PasswordReset.prototype.validateResetToken = function (token) {
1046        var deferred = $q.defer();
1047        var onResult = function (data, status) {
1048            if (data.valid == true) {
1049                deferred.resolve(data);
1050            }
1051            else {
1052                deferred.reject(data);
1053            }
1054        };
1055        var onError = function (data, status) {
1056            deferred.reject(data);
1057        };
1058        $http
1059            .get('/api/v1/passwordreset/' + token)
1060            .success(onResult)
1061            .error(onError);
1062        return deferred.promise;
1063    };
1064    PasswordReset.prototype.resetPassword = function (token, password) {
1065        var deferred = $q.defer();
1066        var onResult = function (data, status) {
1067            vSession.refresh();
1068            deferred.resolve(data);
1069        };
1070        var onError = function (data, status) {
1071            deferred.reject(data);
1072        };
1073        $http
1074            .post('/api/v1/passwordreset/' + token, { password: password })
1075            .success(onResult)
1076            .error(onError);
1077        return deferred.promise;
1078    };
1079    return (window.vPasswordReset = new PasswordReset());
1080});
1081VTMOService.service('vUser', function ($rootScope, $log, Restangular) {
1082    $log = $log.getInstance('vUser');
1083    Restangular.extendModel('users', function (model) {
1084        model.removeAccount = function () {
1085            return model.remove().then(function () {
1086                $rootScope.session.refresh();
1087            });
1088        };
1089        model.lockAccount = function (payload) {
1090            if (payload === void 0) { payload = {}; }
1091            return model.post('lock', payload);
1092        };
1093        model.unlockAccount = function (payload) {
1094            if (payload === void 0) { payload = {}; }
1095            return model.post('unlock', (payload = {}));
1096        };
1097        model.setPassword = function (password, currentPassword) {
1098            var payload = { password: password };
1099            if (currentPassword) {
1100                payload.currentPassword = currentPassword;
1101            }
1102            return model.post('password', payload);
1103        };
1104        model.getNetworks = function () {
1105            return model.getList('networks').then(function (result) {
1106                model.networks = result;
1107            });
1108        };
1109        model.getManagedNetworks = function () {
1110            return model.getList('managednetworks').then(function (result) {
1111                model.managedNetworks = result;
1112            });
1113        };
1114        model.getTripLogs = function () {
1115            return model.getList('triplogs').then(function (result) {
1116                model.tripLogs = result;
1117            });
1118        };
1119        model.getTripPlans = function () {
1120            return model.getList('tripplans').then(function (result) {
1121                model.tripPlans = result;
1122            });
1123        };
1124        model.getTripSearches = function () {
1125            return model.getList('tripsearches').then(function (result) {
1126                model.tripSearches = result;
1127            });
1128        };
1129        model.getCarpoolMessages = function () {
1130            return model.getList('carpoolmessages').then(function (result) {
1131                model.carpoolMessages = result;
1132            });
1133        };
1134        return model;
1135    });
1136    Restangular.extendCollection('users', function (collection) {
1137        collection.register = function (newUserData) {
1138            var onResult = function (result) {
1139                if (result && result.hasOwnProperty('token')) {
1140                    $rootScope.session.refresh();
1141                }
1142                return result;
1143            };
1144            return collection.post(newUserData).then(onResult);
1145        };
1146        collection.getUser = function (user) {
1147            if (typeof user === 'string') {
1148                return Restangular.one('users', user).get();
1149            }
1150            else {
1151                return Restangular.restangularizeElement(null, user, 'users');
1152            }
1153        };
1154        collection.users = collection;
1155        return collection;
1156    });
1157    return (window.vUser = Restangular.all('users'));
1158});
1159VTMOService.service('vPrimaryNetwork', function ($vhttp, CONFIG) {
1160    var primaryNetworkIdToNameMap = new Map();
1161    this.isMultiTenantRewardsProgramEnabled = function () {
1162        return _.get(CONFIG, 'premiumNetworks.multiPrimaryNetworkEnabled', false);
1163    };
1164    this.addNetwork = function (key, value) {
1165        primaryNetworkIdToNameMap.set(key, value);
1166    };
1167    this.getPrimaryNetworkMapSize = function () {
1168        return primaryNetworkIdToNameMap.size;
1169    };
1170    this.getPrimaryNetworkById = function (id) {
1171        return primaryNetworkIdToNameMap.get(id);
1172    };
1173    this.getPrimaryNetworkPropertyValue = function (id, property) {
1174        if (property === void 0) { property = 'name'; }
1175        if (!primaryNetworkIdToNameMap.has(id)) {
1176            return null;
1177        }
1178        var program = primaryNetworkIdToNameMap.get(id);
1179        return _.escape(_.get(program, property));
1180    };
1181    this.setPrimaryNetworkMap = function (userId) {
1182        return __awaiter(this, void 0, void 0, function () {
1183            var programs, e_1;
1184            return __generator(this, function (_a) {
1185                switch (_a.label) {
1186                    case 0:
1187                        _a.trys.push([0, 2, , 3]);
1188                        return [4, $vhttp.get('/api/v1/users/' + userId + '/networks/joined-groups')];
1189                    case 1:
1190                        programs = _a.sent();
1191                        if (programs.length <= 1)
1192                            return [2];
1193                        primaryNetworkIdToNameMap.clear();
1194                        _.forEach(programs, function (program) {
1195                            primaryNetworkIdToNameMap.set(program._id, program);
1196                        });
1197                        return [3, 3];
1198                    case 2:
1199                        e_1 = _a.sent();
1200                        console.error(e_1);
1201                        return [2, false];
1202                    case 3: return [2];
1203                }
1204            });
1205        });
1206    };
1207});
1208VTMOService.service('vNetworks', function ($rootScope, $log, Restangular) {
1209    $log = $log.getInstance('vNetworks');
1210    var privateJoinUrlPrefix = '?join=';
1211    var joinBaseUrl = window.location.protocol;
1212    joinBaseUrl += '//';
1213    joinBaseUrl += window.location.hostname;
1214    if (window.location.port != '') {
1215        joinBaseUrl += ':' + window.location.port;
1216    }
1217    joinBaseUrl += '/#/networks/';
1218    Restangular.extendModel('networks', function (model) {
1219        function setJoinUrl(model) {
1220            model.joinUrl = joinBaseUrl;
1221            model.joinUrl += model._id;
1222            if (!model.isPublic) {
1223                model.joinUrl += '?join=' + model.joinId;
1224            }
1225        }
1226        setJoinUrl(model);
1227        return model;
1228    });
1229    Restangular.extendCollection('networks', function (collection) {
1230        collection.privateJoinUrlPrefix = privateJoinUrlPrefix;
1231        collection.joinBaseUrl = joinBaseUrl;
1232        return collection;
1233    });
1234    return (window.vNetworks = Restangular.all('networks'));
1235});
1236VTMOService.service('vSchoolpools', function ($rootScope, $log, Restangular) {
1237    $log = $log.getInstance('vSchoolpools');
1238    Restangular.extendModel('schoolpools', function (model) {
1239        return model;
1240    });
1241    Restangular.extendCollection('schoolpools', function (collection) {
1242        return collection;
1243    });
1244    return (window.vSchoolpools = Restangular.all('schoolpools'));
1245});
1246VTMOService.service('vEmailTemplates', function ($rootScope, $log, Restangular) {
1247    $log = $log.getInstance('vEmailTemplates');
1248    Restangular.extendModel('templates', function (model) {
1249        return model;
1250    });
1251    Restangular.extendCollection('templates', function (collection) {
1252        return collection;
1253    });
1254    return (window.vEmailTemplates = Restangular.all('email'));
1255});
1256VTMOService.service('vChallengeTeams', function ($rootScope, $log, Restangular) {
1257    $log = $log.getInstance('vChallengeTeams');
1258    Restangular.extendModel('challengeteams', function (model) {
1259        return model;
1260    });
1261    Restangular.extendCollection('challengeteams', function (collection) {
1262        return collection;
1263    });
1264    return (window.vChallengeTeams = Restangular.all('challengeteams'));
1265});
1266VTMOService.service('vTriplogs', function ($rootScope, $log, Restangular) {
1267    $log = $log.getInstance('vTriplogs');
1268    Restangular.extendModel('triplogs', function (model) {
1269        return model;
1270    });
1271    Restangular.extendCollection('triplogs', function (collection) {
1272        return collection;
1273    });
1274    return (window.vTriplogs = Restangular.all('triplogs'));
1275});
1276VTMOService.service('vTriplogreports', function ($rootScope, $log, Restangular) {
1277    $log = $log.getInstance('vTriplogreports');
1278    Restangular.extendModel('triplogreports', function (model) {
1279        return model;
1280    });
1281    Restangular.extendCollection('tripsearches', function (collection) {
1282        return collection;
1283    });
1284    return (window.vTriplogreports = Restangular.all('triplogreports'));
1285});
1286VTMOService.service('vTripsearches', function ($rootScope, $q, $log, $http, Restangular) {
1287    $log = $log.getInstance('vTripsearches');
1288    Restangular.extendModel('tripsearches', function (model) {
1289        var defaultModes = $rootScope.CONFIG.tripplanModes || [
1290            'carpool',
1291            'transit',
1292            'walk',
1293            'bike',
1294            'drive',
1295        ];
1296        model.isValid = function () {
1297            try {
1298                if (model.from == null ||
1299                    model.from.lat == null ||
1300                    model.from.lat == null ||
1301                    model.from.label == null) {
1302                    return false;
1303                }
1304                if (model.to == null ||
1305                    model.to.lat == null ||
1306                    model.to.lat == null ||
1307                    model.to.label == null) {
1308                    return false;
1309                }
1310            }
1311            catch (error) {
1312                return false;
1313            }
1314            return true;
1315        };
1316        return model;
1317    });
1318    Restangular.extendCollection('tripsearches', function (collection) {
1319        collection.fromObject = function (searchObject) {
1320            return Restangular.restangularizeElement(null, searchObject, 'tripsearches');
1321        };
1322        collection.search = function (plan) {
1323            $log.debug('tripsearches: collection.search(plan)', plan);
1324            var params = {
1325                modes: angular.isDefined(plan.modes) ? plan.modes : defaultModes,
1326                date: plan.date ? plan.date : moment().format('MM/DD/YYYY'),
1327                time: plan.time ? plan.time : moment().format('HH:mm a'),
1328                from: plan.from,
1329                to: plan.to,
1330                waypoints: [plan.from, plan.to],
1331            };
1332            if (plan.arriveBy)
1333                params.arriveBy = plan.arriveBy;
1334            if (plan.event || plan.relatedEvent) {
1335                params.relatedEvent = plan.event || plan.relatedEvent;
1336            }
1337            return $http.post('/api/v1/tripsearch/search', params);
1338        };
1339        return collection;
1340    });
1341    return (window.vTripsearches = Restangular.all('tripsearches'));
1342});
1343VTMOService.service('vTripplans', function ($rootScope, $log, Restangular) {
1344    $log = $log.getInstance('vTripplans');
1345    Restangular.extendModel('tripplans', function (model) {
1346        return model;
1347    });
1348    Restangular.extendCollection('tripplans', function (collection) {
1349        return collection;
1350    });
1351    return (window.vTripplans = Restangular.all('tripplans'));
1352});
1353VTMOService.service('vPDFRequests', function ($rootScope, $log, $timeout, Restangular) {
1354    $log = $log.getInstance('vPDFRequests');
1355    Restangular.extendModel('pdfrequests', function (model) {
1356        model.restart = function () {
1357            $log.debug('regenerate PDF');
1358            return model.refresh(true);
1359        };
1360        model.watch = function (reload) {
1361            $log.debug('watch', reload, model.status);
1362            if (model.status !== 'new' &&
1363                model.status !== 'complete' &&
1364                model.status !== 'error') {
1365                model.watching = true;
1366                if (reload) {
1367                    model.refresh();
1368                }
1369                else {
1370                    $timeout(function () {
1371                        model.watch(true);
1372                    }, 1000);
1373                }
1374            }
1375            else {
1376                model.watching = false;
1377            }
1378        };
1379        model.refresh = function (restartRequest) {
1380            return model
1381                .get(null, { startRequest: restartRequest === true })
1382                .then(function (updated) {
1383                _.assignWith(model, updated, function (modelValue, updateValue) {
1384                    if (typeof updateValue !== 'function') {
1385                        return updateValue;
1386                    }
1387                    else {
1388                        return modelValue;
1389                    }
1390                });
1391                model.watch();
1392            });
1393        };
1394        return model;
1395    });
1396    Restangular.extendCollection('pdfrequests', function (collection) {
1397        return collection;
1398    });
1399    return (window.vPDFRequests = Restangular.all('pdfrequests'));
1400});
1401VTMOService.service('vEmailRequests', function ($rootScope, $log, $timeout, Restangular) {
1402    $log = $log.getInstance('vEmailRequests');
1403    Restangular.extendModel('emailrequests', function (model) {
1404        model.restart = function () {
1405            $log.debug('regenerate PDF');
1406            return model.refresh(true);
1407        };
1408        model.watch = function (reload) {
1409            $log.debug('watch', reload, model.status);
1410            if (model.status !== 'complete' && model.status !== 'error') {
1411                model.watching = true;
1412                if (reload) {
1413                    model.refresh();
1414                }
1415                else {
1416                    $timeout(function () {
1417                        model.watch(true);
1418                    }, 1000);
1419                }
1420            }
1421            else {
1422                model.watching = false;
1423            }
1424        };
1425        model.refresh = function (restartRequest) {
1426            return model
1427                .get(null, { startRequest: restartRequest === true })
1428                .then(function (updated) {
1429                _.assignWith(model, updated, function (modelValue, updateValue) {
1430                    if (typeof updateValue !== 'function') {
1431                        return updateValue;
1432                    }
1433                    else {
1434                        return modelValue;
1435                    }
1436                });
1437                model.watch();
1438            });
1439        };
1440        return model;
1441    });
1442    Restangular.extendCollection('emailrequests', function (collection) {
1443        return collection;
1444    });
1445    return (window.vEmailRequests = Restangular.all('emailrequests'));
1446});
1447VTMOService.service('vSurveys', function ($rootScope, $log, Restangular) {
1448    $log = $log.getInstance('surveys');
1449    Restangular.extendModel('surveys', function (model) {
1450        function isQuestionContent(content) {
1451            return content.contentType === 'question';
1452        }
1453        var questions = _.map(_.filter(model.content, isQuestionContent), 'question');
1454        model.questions = questions;
1455        return model;
1456    });
1457    Restangular.extendCollection('surveys', function (collection) {
1458        collection.newSurveyFromTemplate = function (template) {
1459            var newSurvey = {};
1460            newSurvey.template = template._id;
1461            newSurvey.type = template.type;
1462            newSurvey.surveyTitle = template.templateSurveyTitle || null;
1463            newSurvey.content = _.clone(template.content);
1464            newSurvey.availableReports = _.clone(template.availableReports);
1465            newSurvey.customSuccessMessage = template.customSuccessMessage || null;
1466            newSurvey.status = 'draft';
1467            return Restangular.restangularizeElement(null, newSurvey, 'surveys');
1468        };
1469        return collection;
1470    });
1471    return (window.vSurveys = Restangular.all('surveys'));
1472});
1473VTMOService.service('vChallenges', function ($rootScope, $log, Restangular) {
1474    $log = $log.getInstance('vChallenges');
1475    Restangular.extendModel('challenges', function (model) {
1476        model.canUserManage = function (user) {
1477            var challenge = this;
1478            if (!user)
1479                return false;
1480            if (user.isAdmin)
1481                return true;
1482            return _.some(user.managedNetworks, function (n) {
1483                return _.includes(challenge.managingNetworks, n);
1484            });
1485            return false;
1486        };
1487        return model;
1488    });
1489    Restangular.extendCollection('challenges', function (collection) {
1490        return collection;
1491    });
1492    return (window.vChallenges = Restangular.all('challenges'));
1493});
1494VTMOService.service('vIncentives', function ($rootScope, $log, Restangular) {
1495    $log = $log.getInstance('vIncentives');
1496    Restangular.extendModel('incentives', function (model) {
1497        model.canUserManage = function (user) {
1498            var incentive = this;
1499            if (user.isAdmin)
1500                return true;
1501            return _.some(user.managedNetworks, function (n) {
1502                return _.includes(incentive.managingNetworks, n);
1503            });
1504            return false;
1505        };
1506        return model;
1507    });
1508    Restangular.extendCollection('incentives', function (collection) {
1509        return collection;
1510    });
1511    return (window.vIncentives = Restangular.all('incentives'));
1512});
1513VTMOService.service('vPointPrograms', function ($rootScope, $log, Restangular) {
1514    $log = $log.getInstance('vPointPrograms');
1515    Restangular.extendModel('pointPrograms', function (model) {
1516        model.canUserManage = function (user) {
1517            var pointProgram = this;
1518            if (user.isAdmin)
1519                return true;
1520            return _.some(user.managedNetworks, function (n) {
1521                return _.includes(pointProgram.managingNetworks, n);
1522            });
1523            return false;
1524        };
1525        return model;
1526    });
1527    Restangular.extendCollection('pointPrograms', function (collection) {
1528        return collection;
1529    });
1530    return (window.vPointPrograms = Restangular.all('pointprograms'));
1531});
1532VTMOService.service('vEvents', function ($rootScope, $log, Restangular) {
1533    $log = $log.getInstance('vEvents');
1534    Restangular.extendModel('events', function (model) {
1535        return model;
1536    });
1537    Restangular.extendCollection('events', function (collection) {
1538        return collection;
1539    });
1540    return (window.vEvents = Restangular.all('events'));
1541});
1542VTMOService.service('ShortURL', function ($rootScope, $log, Restangular, $q, $timeout) {
1543    $log = $log.getInstance('ShortURL');
1544    Restangular.extendModel('shorturls', function (model) {
1545        model.updateSlug = function (newSlug) {
1546            return model.one('slug').customPUT({ slug: newSlug });
1547        };
1548        model.getBaseURL = function () {
1549            var baseURL = window.location.protocol;
1550            baseURL += '//';
1551            baseURL += window.location.hostname;
1552            if (window.location.port != '') {
1553                baseURL += ':' + window.location.port;
1554            }
1555            baseURL += '/s/';
1556            return baseURL;
1557        };
1558        model.getFullURL = function () {
1559            var fullURL = model.getBaseURL() + this.slug;
1560            return fullURL;
1561        };
1562        model.baseURL = model.getBaseURL();
1563        model.fullURL = model.getFullURL();
1564        return model;
1565    });
1566    Restangular.extendCollection('shorturls', function (collection) {
1567        collection.getFullPath = function (slug) {
1568            return collection.all('slug').one(slug).one('path').get();
1569        };
1570        collection.getShortURL = function (shortURL) {
1571            var deferred = $q.defer();
1572            if (shortURL && typeof shortURL === 'string') {
1573                return Restangular.one('shorturls', shortURL).get();
1574            }
1575            else if (shortURL) {
1576                $timeout(function () {
1577                    var model = Restangular.restangularizeElement(null, shortURL, 'shorturls');
1578                    deferred.resolve(model);
1579                });
1580            }
1581            else {
1582                $timeout(function () {
1583                    deferred.resolve(null);
1584                });
1585            }
1586            return deferred.promise;
1587        };
1588        return collection;
1589    });
1590    return (window.ShortURL = Restangular.all('shorturls'));
1591});
1592VTMOService.service('BulkEmailService', function ($log, $http, $q) {
1593    $log = $log.getInstance('BulkEmailService');
1594    function getEmailTemplates() {
1595        var deferred = $q.defer();
1596        $http
1597            .get('/api/v1/email/templates')
1598            .success(function (data) {
1599            deferred.resolve(data);
1600        })
1601            .error(function (error) {
1602            deferred.reject(error);
1603        });
1604        return deferred.promise;
1605    }
1606    function getEmailTemplateById(id) {
1607        var deferred = $q.defer();
1608        $http
1609            .get('/api/v1/email/templates/' + id)
1610            .success(function (data) {
1611            deferred.resolve(data);
1612        })
1613            .error(function (error) {
1614            deferred.reject(error);
1615        });
1616        return deferred.promise;
1617    }
1618    function createEmailTemplate(emailTemplate) {
1619        var deferred = $q.defer();
1620        $http
1621            .post('/api/v1/email/templates', emailTemplate)
1622            .success(function (data) {
1623            deferred.resolve(data);
1624        })
1625            .error(function (error) {
1626            deferred.reject(error);
1627        });
1628        return deferred.promise;
1629    }
1630    function updateEmailTemplate(emailTemplate) {
1631        var deferred = $q.defer();
1632        $http
1633            .put('/api/v1/email/templates/' + emailTemplate._id, emailTemplate)
1634            .success(function (data) {
1635            deferred.resolve(data);
1636        })
1637            .error(function (error) {
1638            deferred.reject(error);
1639        });
1640        return deferred.promise;
1641    }
1642    function deleteEmailTemplate(id) {
1643        var deferred = $q.defer();
1644        $http
1645            .delete('/api/v1/email/templates/' + id)
1646            .success(function (data) {
1647            deferred.resolve(data);
1648        })
1649            .error(function (error) {
1650            deferred.reject(error);
1651        });
1652        return deferred.promise;
1653    }
1654    function deleteBulkEmailRequest(id) {
1655        var deferred = $q.defer();
1656        $http
1657            .delete('/api/v1/email/' + id)
1658            .success(function (data) {
1659            deferred.resolve(data);
1660        })
1661            .error(function (error) {
1662            deferred.reject(error);
1663        });
1664        return deferred.promise;
1665    }
1666    function sendBulkEmail(req) {
1667        var deferred = $q.defer();
1668        $http
1669            .post('/api/v1/email', req)
1670            .success(function (data) {
1671            deferred.resolve(data);
1672        })
1673            .error(function (error) {
1674            deferred.reject(error);
1675        });
1676        return deferred.promise;
1677    }
1678    function getCurrentEmailRequests() {
1679        var deferred = $q.defer();
1680        $http
1681            .get('/api/v1/email')
1682            .success(function (data) {
1683            deferred.resolve(data);
1684        })
1685            .error(function (error) {
1686            deferred.reject(error);
1687        });
1688        return deferred.promise;
1689    }
1690    function getNetworkEmailRequests(netId) {
1691        var deferred = $q.defer();
1692        $http
1693            .get('/api/v1/email/networks/' + netId)
1694            .success(function (data) {
1695            deferred.resolve(data);
1696        })
1697            .error(function (error) {
1698            deferred.reject(error);
1699        });
1700        return deferred.promise;
1701    }
1702    function getEmailSendStatus(id) {
1703        var deferred = $q.defer();
1704        $http
1705            .get('/api/v1/email/' + id)
1706            .success(function (data) {
1707            deferred.resolve(data);
1708        })
1709            .error(function (error) {
1710            deferred.reject(error);
1711        });
1712        return deferred.promise;
1713    }
1714    return (window.BulkEmailService = {
1715        getEmailTemplateById: getEmailTemplateById,
1716        getEmailTemplates: getEmailTemplates,
1717        createEmailTemplate: createEmailTemplate,
1718        updateEmailTemplate: updateEmailTemplate,
1719        deleteEmailTemplate: deleteEmailTemplate,
1720        deleteBulkEmailRequest: deleteBulkEmailRequest,
1721        sendBulkEmail: sendBulkEmail,
1722        getCurrentEmailRequests: getCurrentEmailRequests,
1723        getEmailSendStatus: getEmailSendStatus,
1724        getNetworkEmailRequests: getNetworkEmailRequests,
1725    });
1726});
1727VTMOService.service('Geocode', function ($rootScope, $log, $http, $q, Restangular) {
1728    $log = $log.getInstance('Geocode');
1729    function address(addressData) {
1730        var deferred = $q.defer();
1731        $http
1732            .post('/api/v1/geocode/address', addressData)
1733            .success(function (data) {
1734            deferred.resolve(data);
1735        })
1736            .error(function (error) {
1737            deferred.reject(error);
1738        });
1739        return deferred.promise;
1740    }
1741    function getLocation(magicKey, text) {
1742        var deferred = $q.defer();
1743        var params = {
1744            text: text,
1745            magicKey: magicKey,
1746        };
1747        $http
1748            .get('/api/v1/geocode/suggestions', { params: params })
1749            .success(function (data) {
1750            deferred.resolve(data);
1751        })
1752            .error(function (error) {
1753            deferred.reject(error);
1754        });
1755        return deferred.promise;
1756    }
1757    function reverse(lat, lng) {
1758        return Restangular.all('geocode')
1759            .one('reverse')
1760            .get({ lat: lat, lng: lng });
1761    }
1762    function autocomplete(text, category) {
1763        if (category === void 0) { category = null; }
1764        var deferred = $q.defer();
1765        var params = {
1766            text: text,
1767            category: category,
1768        };
1769        var location;
1770        try {
1771            location =
1772                $rootScope.session.user.workLocation.geometry.coordinates.join(',');
1773        }
1774        catch (e) {
1775            console.warn('no user location');
1776        }
1777        if (location) {
1778            params.location = location;
1779        }
1780        $http
1781            .get('/api/v1/geocode/autocomplete2', { params: params })
1782            .success(function (data) {
1783            deferred.resolve(data);
1784        })
1785            .error(function (error) {
1786            deferred.reject(error);
1787        });
1788        return deferred.promise;
1789    }
1790    function getCollection(magicKey, text) {
1791        var deferred = $q.defer();
1792        var params = {
1793            singleLine: text,
1794            magicKey: magicKey,
1795        };
1796        $http
1797            .get('/api/v1/geocode/collections', { params: params })
1798            .success(function (data) {
1799            deferred.resolve(data);
1800        })
1801            .error(function (error) {
1802            deferred.reject(error);
1803        });
1804        return deferred.promise;
1805    }
1806    return (window.Geocode = {
1807        address: address,
1808        reverse: reverse,
1809        autocomplete: autocomplete,
1810        getLocation: getLocation,
1811        getCollection: getCollection,
1812    });
1813});
1814VTMOService.service('Locations', function ($rootScope, $log, Restangular, $http, $q) {
1815    Restangular.extendCollection('locations', function (collection) {
1816        collection.getCategories = function () {
1817            var deferred = $q.defer();
1818            $http.get('/api/v1/locations/categories').then(function (data) {
1819                deferred.resolve(data.data);
1820            });
1821            return deferred.promise;
1822        };
1823        return collection;
1824    });
1825    return (window.Locations = Restangular.all('locations'));
1826});
1827VTMOService.service('vFacebook', function ($rootScope, $log, $q, $timeout) {
1828    $log = $log.getInstance('vFacebook');
1829    var FacebookClient = function () {
1830        this.appId = undefined;
1831        this.status = this.STATUS.NOT_INITIALIZED;
1832        this.facebookAccessToken = undefined;
1833        this.facebookId = undefined;
1834        this.facebookUser = undefined;
1835        this.scope = { scope: 'email' };
1836    };
1837    FacebookClient.prototype.STATUS = {
1838        NOT_INITIALIZED: 'not_initialized',
1839        INITIALIZED: 'initialized',
1840        NOT_CONNECTED: 'not_connected',
1841        CONNECTED: 'connected',
1842        NOT_AUTHORIZED: 'not_authorized',
1843    };
1844    FacebookClient.prototype.init = function (appId, scope) {
1845        $log.debug('init(appId,scope)', appId, scope);
1846        if (appId) {
1847            this.appId = appId;
1848        }
1849        if (scope) {
1850            this.scope = scope;
1851        }
1852        this.loadFBSdk();
1853    };
1854    FacebookClient.prototype.loadFBSdk = function () {
1855        $log.debug('loadFBSdk()');
1856        window.fbAsyncInit = this.onFacebookSDKAvailable;
1857        window.vFBClient = this;
1858        var js, id = 'facebook-jssdk', ref = document.getElementsByTagName('script')[0];
1859        if (document.getElementById(id)) {
1860            return;
1861        }
1862        js = document.createElement('script');
1863        js.id = id;
1864        js.async = true;
1865        js.src = '//connect.facebook.net/en_US/all.js';
1866        ref.parentNode.insertBefore(js, ref);
1867    };
1868    FacebookClient.prototype.onFacebookSDKAvailable = function () {
1869        $log.debug('onFacebookSDKAvailable()');
1870        var client = window.vFBClient;
1871        FB.init({
1872            appId: client.appId,
1873            status: true,
1874            cookie: true,
1875            xfbml: true,
1876        });
1877        FB.Event.subscribe('auth.statusChange', function (response) {
1878            $rootScope.$apply(function () {
1879                client.onAuthStatusChange(response);
1880            });
1881        });
1882        client.status = client.STATUS.INITIALIZED;
1883        $rootScope.$apply();
1884    };
1885    FacebookClient.prototype.onAuthStatusChange = function (response) {
1886        $log.debug('onAuthStatusChange(response)', response);
1887        var client = this;
1888        var status = response == null ? null : response.status;
1889        switch (status) {
1890            case 'connected':
1891                this.facebookId = response.authResponse.userID;
1892                this.facebookAccessToken = response.authResponse.accessToken;
1893                this.facebookUser = { id: response.authResponse.userID };
1894                this.status = this.STATUS.CONNECTED;
1895                client.updateUserDetails();
1896                break;
1897            case 'not_authorized':
1898                this.facebookId = undefined;
1899                this.facebookAccessToken = undefined;
1900                this.facebookUser = undefined;
1901                this.status = this.STATUS.NOT_AUTHORIZED;
1902                break;
1903            case 'unknown':
1904            default:
1905                this.facebookId = undefined;
1906                this.facebookAccessToken = undefined;
1907                this.facebookUser = undefined;
1908                this.status = this.STATUS.NOT_CONNECTED;
1909                break;
1910        }
1911    };
1912    FacebookClient.prototype.getLoginStatus = function () {
1913        $log.debug('getLoginStatus()');
1914        var deferred = $q.defer();
1915        var client = this;
1916        FB.getLoginStatus(function (response) {
1917            deferred.resolve(this);
1918        });
1919        return deferred.promise;
1920    };
1921    FacebookClient.prototype.connect = function () {
1922        $log.debug('connect()');
1923        var deferred = $q.defer();
1924        var client = this;
1925        FB.login(function (response) {
1926            if (response && response.status != 'unknown') {
1927                deferred.resolve(this);
1928            }
1929            else {
1930                deferred.reject(this);
1931            }
1932        }, client.scope);
1933        return deferred.promise;
1934    };
1935    FacebookClient.prototype.logout = function () {
1936        $log.debug('logout()');
1937        var deferred = $q.defer();
1938        var client = this;
1939        FB.logout(function (response) {
1940            if (response) {
1941                deferred.resolve(this);
1942            }
1943            else {
1944                deferred.reject(this);
1945            }
1946        });
1947        return deferred.promise;
1948    };
1949    FacebookClient.prototype.disconnect = function () {
1950        $log.debug('disconnect()');
1951        var deferred = $q.defer();
1952        var client = this;
1953        FB.api('/me/permissions', 'DELETE', function (response) {
1954            if (response) {
1955                deferred.resolve(this);
1956            }
1957            else {
1958                deferred.reject(this);
1959            }
1960        });
1961        return deferred.promise;
1962    };
1963    FacebookClient.prototype.updateUserDetails = function () {
1964        $log.debug('updateUserDetails()');
1965        var deferred = $q.defer();
1966        var client = this;
1967        if (client.status !== client.STATUS.CONNECTED) {
1968            $timeout(function () {
1969                deferred.reject({ error: 'Not Connected' });
1970            });
1971        }
1972        else {
1973            FB.api('/me?fields=first_name,last_name,email,picture', 'GET', function (response) {
1974                if (response) {
1975                    $rootScope.$apply(function () {
1976                        client.facebookUser = response;
1977                        deferred.resolve(this);
1978                    });
1979                }
1980                else {
1981                    deferred.reject();
1982                }
1983            });
1984        }
1985        return deferred.promise;
1986    };
1987    return (window.facebook = $rootScope.facebook = new FacebookClient());
1988});
1989VTMOService.service('Dialogs', function ($rootScope) {
1990    vex.defaultOptions.className = 'vex-theme-default';
1991    vex.defaultOptions.closeAllOnPopState = false;
1992    var toast = $('#toast')
1993        .kendoNotification({
1994        position: {
1995            pinned: true,
1996            top: 30,
1997            right: 30,
1998        },
1999        autoHideAfter: 2500,
2000        stacking: 'down',
2001        templates: [
2002            {
2003                type: 'toast-success',
2004                template: '<div class="success-toast"><h3><i class="fa fa-check-circle-o pull-left"></i> #= message #</h3></div>',
2005            },
2006            {
2007                type: 'toast-warning',
2008                template: '<div class="warning-toast"><h3><i class="fa fa-exclamation-circle pull-left"></i> #= message #</h3></div>',
2009            },
2010        ],
2011    })
2012        .data('kendoNotification');
2013    vex.dialog.successToast = function (message) {
2014        toast.show({
2015            message: message,
2016        }, 'toast-success');
2017    };
2018    vex.dialog.warningToast = function (message) {
2019        toast.show({
2020            message: message,
2021        }, 'toast-warning');
2022    };
2023    return vex.dialog;
2024});
2025VTMOService.service('URLService', function () {
2026    function getBaseUrl() {
2027        var baseURL = window.location.protocol;
2028        baseURL += '//';
2029        baseURL += window.location.hostname;
2030        if (window.location.port != '') {
2031            baseURL += ':' + window.location.port;
2032        }
2033        return baseURL;
2034    }
2035    function getRelativeUrl(path) {
2036        return getBaseUrl() + path;
2037    }
2038    return {
2039        getBaseUrl: getBaseUrl,
2040        getRelativeUrl: getRelativeUrl,
2041    };
2042});
2043;
2044'use strict';
2045var appControllers = angular.module('vtmoFront');
2046appControllers.controller('AccountLoginController', function ($scope, $rootScope, vSession, $state, $log, Dialogs, AccountResolvingService) {
2047    'use strict';
2048    $log = $log.getInstance('AccountLoginController');
2049    if ($scope.session.user)
2050        return $scope.globalModalHide();
2051    $scope.providers = sortProviders();
2052    $rootScope.tempRegScope = $rootScope.tempRegScope || {};
2053    if ($rootScope.tempRegScope)
2054        _.assign($scope, $rootScope.tempRegScope);
2055    function sortProviders() {
2056        return CONFIG.account.providers.sort(function (a, b) {
2057            if (a.type !== 'email')
2058                return -1;
2059            if (a.type === 'email')
2060                return 1;
2061            return 0;
2062        });
2063    }
2064    if ($scope.devScope) {
2065        $scope.user = {
2066            email: '[email protected]',
2067            password: 'password',
2068        };
2069    }
2070    $scope.user = {};
2071    if ($rootScope.emailInput)
2072        $scope.user.email = $rootScope.emailInput;
2073    $scope.$watch('user.email', function (emailInput) {
2074        $rootScope.emailInput = $rootScope.EMAIL_REGEXP.test(emailInput)
2075            ? emailInput
2076            : null;
2077    });
2078    function getRedirectUrl() {
2079        var pendingState = $rootScope.pendingState;
2080        var queryParamStrings = [];
2081        _.forEach(pendingState.search, function (value, key) {
2082            queryParamStrings.push(key + '=' + value);
2083        });
2084        _.apply(pendingState.params, pendingState.search);
2085        var url = $state.href(pendingState.state, pendingState.params);
2086        if (queryParamStrings.length) {
2087            url += '?' + queryParamStrings.join('&');
2088        }
2089        if (url[0] !== '/')
2090            url = '/' + url;
2091        return encodeURIComponent(url);
2092    }
2093    $scope.externalLogin = function (path) {
2094        if ($rootScope.pendingState) {
2095            var redirectUrl = getRedirectUrl();
2096            if (path === '/sso/saml') {
2097                path = path + '?RelayState=' + redirectUrl;
2098            }
2099            else if (path === '/sso/google') {
2100                path = path + '?redirect=' + redirectUrl;
2101            }
2102        }
2103        window.location = path;
2104    };
2105    $scope.login = function (user) {
2106        vSession.emailLogin(user.email, user.password).then(function (data) {
2107            $scope.globalModalHide();
2108        }, function (error) {
2109            $log.debug(error);
2110            AccountResolvingService.handleError(error);
2111        });
2112    };
2113    $scope.$watch('facebook.facebookAccessToken', function (token) {
2114        facebookShowRegistration();
2115    });
2116    $scope.$watch('session.user', function (user) {
2117        if (user)
2118            $scope.globalModalHide();
2119    });
2120    function facebookShowRegistration() {
2121        'use strict';
2122        if ($scope.facebook.facebookAccessToken && !$scope.session.user) {
2123            $scope.globalModalShow('account.register');
2124        }
2125    }
2126});
2127appControllers.controller('AccountLogoutController', function ($scope, $rootScope, vSession, $state, Dialogs, $log) {
2128    'use strict';
2129    $log = $log.getInstance('AccountLogoutController');
2130    $scope.logout = function () {
2131        delete $rootScope.emailInput;
2132        if (facebook.facebookUser)
2133            $rootScope.facebook.logout();
2134        if (window.gapi && gapi.auth2.getAuthInstance().isSignedIn.get())
2135            gapi.auth2.getAuthInstance().disconnect();
2136        $scope.session.logout();
2137        $state.go('home');
2138    };
2139});
2140appControllers.controller('AccountRegisterController', function ($scope, $rootScope, vUser, vSession, $state, $filter, vNetworks, Dialogs, $log, $timeout, AccountResolvingService) {
2141    'use strict';
2142    $log = $log.getInstance('AccountRegisterController');
2143    if ($scope.session.user)
2144        return $scope.globalModalHide();
2145    $scope.user = {};
2146    $scope.user.networks = [];
2147    $scope.user.source = $rootScope.registrationSource;
2148    $scope.pendingResponse = false;
2149    $scope.selectedNetworks = [];
2150    var autoSelectNetworkId = $state.params && $state.params.networkId ? $state.params.networkId : null;
2151    var autoSelectNetworkJoinId = $state.params && $state.params.join ? $state.params.join : null;
2152    var failSafeTime = 5000;
2153    var retry = true;
2154    if ($rootScope.autoSelectNetworkId)
2155        autoSelectNetworkId = $rootScope.autoSelectNetworkId;
2156    if ($rootScope.autoSelectNetworkJoinId)
2157        autoSelectNetworkJoinId = $rootScope.autoSelectNetworkJoinId;
2158    if ($scope.devScope) {
2159        $scope.user = {
2160            email: '[email protected]',
2161            password: 'password',
2162            firstName: 'firstName',
2163            lastName: 'lastName',
2164            homeZip: '47404',
2165        };
2166    }
2167    $rootScope.tempRegScope = $rootScope.tempRegScope || {};
2168    if ($rootScope.tempRegScope)
2169        _.assign($scope, $rootScope.tempRegScope);
2170    if ($rootScope.emailInput && $scope.user)
2171        $scope.user.email = $rootScope.emailInput;
2172    $scope.$watchCollection('user', function (user) {
2173        $rootScope.tempRegScope.user = angular.copy(user);
2174        $rootScope.tempRegScope.showStep2 = angular.copy($scope.showStep2);
2175        $rootScope.emailInput = $rootScope.tempRegScope.user.email =
2176            $rootScope.EMAIL_REGEXP.test(user.email) ? user.email : undefined;
2177    });
2178    $scope.$watchCollection('selectedNetworks', function (selectedNetworks) {
2179        $rootScope.tempRegScope.selectedNetworks = angular.copy(selectedNetworks);
2180    });
2181    vNetworks.getList().then(function (networks) {
2182        $scope.availableNetworks = $filter('orderBy')(networks, 'name');
2183        if (autoSelectNetworkId) {
2184            var joinThisNet = _.filter($scope.availableNetworks, {
2185                _id: autoSelectNetworkId,
2186            });
2187            if (joinThisNet.length === 1)
2188                $scope.selectedNetworks.push(joinThisNet[0]);
2189        }
2190    });
2191    $scope.deselectNetwork = function (network) {
2192        $scope.selectedNetworks = _.pull($scope.selectedNetworks, network);
2193    };
2194    $scope.setShowStep2 = function (val) {
2195        $scope.showStep2 = val;
2196    };
2197    $rootScope.newRegistrationSuccess = false;
2198    $scope.register = function (user) {
2199        $scope.pendingResponse = true;
2200        requestFailSafe(user);
2201        vUser.users.register(user).then(function (data) {
2202            resetFailSafe();
2203            $scope.globalModalHide();
2204            $rootScope.newRegistrationSuccess = true;
2205            delete $rootScope.tempRegScope;
2206            if (data.confirmationRequired) {
2207                Dialogs.alert('All set. Now just check your email and click the confirmation link to access your account!');
2208                ga('send', 'event', 'form submission', 'submit', 'registration');
2209            }
2210            else {
2211                Dialogs.alert('Welcome! Your account has been created and you are now logged in.');
2212                ga('send', 'event', 'form submission', 'submit', 'registration');
2213            }
2214        }, function (error) {
2215            resetFailSafe();
2216            AccountResolvingService.handleError(error);
2217        });
2218    };
2219    function resetFailSafe() {
2220        retry = true;
2221        failSafeTime = 5000;
2222        $scope.pendingResponse = false;
2223    }
2224    function requestFailSafe(payload) {
2225        $timeout(function () {
2226            if ($scope.pendingResponse) {
2227                if (retry) {
2228                    return retryRequest(payload);
2229                }
2230                serverUnresponsive();
2231            }
2232        }, failSafeTime);
2233    }
2234    function retryRequest(payload) {
2235        retry = false;
2236        failSafeTime = 2500;
2237        return $scope.register(payload);
2238    }
2239    function serverUnresponsive() {
2240        resetFailSafe();
2241        vex.closeTop();
2242        Dialogs.alert('There was problem creating your account, please check your internet connection and that you have completed all the fields.');
2243    }
2244    $scope.$watch('facebook.facebookUser', function (user) {
2245        if (user) {
2246            $scope.showStep2 = true;
2247            $scope.user.facebookPhotoUrl =
2248                'http://graph.facebook.com/' + user.id + '/picture';
2249            $scope.user.firstName = user.first_name;
2250            $scope.user.lastName = user.last_name;
2251            $scope.user.email = user.email;
2252            $scope.user.facebookAccessToken = $scope.facebook.facebookAccessToken;
2253            $scope.user.password = undefined;
2254        }
2255        else {
2256            if ($scope.user)
2257                $scope.user.facebookAccessToken = undefined;
2258        }
2259    });
2260});
2261appControllers.controller('AustinADLFormController', function ($scope, moment, vSession, DigitalInventoryManagementService, Dialogs, Restangular, vNetworks) {
2262    $scope.$watch('session.user', function (user) {
2263        if (user) {
2264            $scope.user = Restangular.copy(user);
2265            updateNetworks();
2266        }
2267        else
2268            $scope.user = null;
2269    });
2270    $scope.userNetworks = [];
2271    function updateNetworks() {
2272        $scope.user.getList('networks').then(function (networks) {
2273            $scope.userNetworks = networks;
2274            vNetworks.getList().then(function (networks) {
2275                networks = _.sortBy(networks, 'name');
2276                var networkData = [];
2277                _.forEach(networks, function (net) {
2278                    if (!_.includes(_.map($scope.userNetworks, '_id'), net._id))
2279                        networkData.push({
2280                            id: net._id,
2281                            text: net.name,
2282                            network: net,
2283                        });
2284                });
2285                $('#networkSearch')
2286                    .off('change')
2287                    .select2({
2288                    data: networkData,
2289                    formatResult: function (net) {
2290                        var networkRendererHTML = '<p>' +
2291                            '<b><var networkName>' +
2292                            _.escape(net.network.name) +
2293                            '</var></b> ' +
2294                            '<small>(' +
2295                            net.network.type +
2296                            ')</small>' +
2297                            '</p>';
2298                        return networkRendererHTML;
2299                    },
2300                });
2301            });
2302        });
2303    }
2304});
2305appControllers.controller('AustinRegistrationExtras', function ($scope, vNetworks, $rootScope, $state, $sanitize, Restangular, vSession, vUser, Dialogs, $log, $timeout, SessionUserDataService, $window) {
2306    vNetworks
2307        .getList({ tags: 'department' })
2308        .then(function (departmentNetworks) {
2309        $scope.departmentNetworks = departmentNetworks;
2310    });
2311    $scope.$watch('departmentNetwork', function (departmentNetwork, oldDepartmentNetwork) {
2312        if (oldDepartmentNetwork && $scope.user.networks) {
2313            _.remove($scope.user.networks, function (network) {
2314                return network === oldDepartmentNetwork;
2315            });
2316        }
2317        if (departmentNetwork)
2318            $scope.user.networks.push(departmentNetwork);
2319    });
2320});
2321appControllers.controller('AustinSubsiteExtras', function ($scope, vNetworks, $rootScope, $state, $sanitize, $filter, Restangular, vSession, vUser, Dialogs, $log, $timeout, SessionUserDataService, $window, AccountResolvingService, elementHelper) {
2322    $scope.$watch('session.user', function (user) {
2323        if (user) {
2324            $scope.user = Restangular.copy(user);
2325            updateNetworks();
2326        }
2327        else
2328            $scope.user = null;
2329    });
2330    $scope.update = function () {
2331        $scope.user.customProfileFields.adlFormSubmitted = true;
2332        $scope.user.put().then(function () {
2333            Dialogs.successToast('Your changes were saved.');
2334            vSession.refresh();
2335            elementHelper.scrollToElement(document.getElementById('step4'), 275);
2336        }, function (err) {
2337            err.type = 'POST';
2338            AccountResolvingService.handleError(err);
2339        });
2340    };
2341    $scope.userNetworks = [];
2342    function updateNetworks() {
2343        $scope.user.getList('networks').then(function (networks) {
2344            $scope.userNetworks = networks;
2345            vNetworks.getList().then(function (networks) {
2346                networks = _.sortBy(networks, 'name');
2347                var networkData = [];
2348                _.forEach(networks, function (net) {
2349                    if (!_.includes(_.map($scope.userNetworks, '_id'), net._id) &&
2350                        net.name.includes('Administrative Leave (ADL) Reward - Test'))
2351                        networkData.push({
2352                            id: net._id,
2353                            text: net.name,
2354                            network: net,
2355                        });
2356                });
2357                $('#networkSearch')
2358                    .off('change')
2359                    .select2({
2360                    data: networkData,
2361                    formatResult: function (net) {
2362                        var networkRendererHTML = '<p>' +
2363                            '<b><var networkName>' +
2364                            _.escape(net.network.name) +
2365                            '</var></b> ' +
2366                            '<small>(' +
2367                            net.network.type +
2368                            ')</small>' +
2369                            '</p>';
2370                        var parentNetworkNames = _.map(net.network.ancestors, 'name');
2371                        if (parentNetworkNames.length > 0) {
2372                            networkRendererHTML +=
2373                                "<p><small class='text-muted'><i><b isolate>Parent Network:</b><span notranslate> " +
2374                                    _.escape(parentNetworkNames.join(', ')) +
2375                                    '</span></i></small></p>';
2376                        }
2377                        if (net.network.description) {
2378                            networkRendererHTML +=
2379                                '<p><i><var description>' +
2380                                    $sanitize($filter('markdownToHTML')(net.network.description)) +
2381                                    '</var></i></p><hr />';
2382                        }
2383                        if (!net.network.description) {
2384                            networkRendererHTML += '<hr />';
2385                        }
2386                        return networkRendererHTML;
2387                    },
2388                })
2389                    .on('change', function (e) {
2390                    $(e.target).val('');
2391                    if (e.val)
2392                        $scope.$apply(function () {
2393                            addUserToNetwork(e.val);
2394                        });
2395                });
2396            });
2397        });
2398    }
2399    $scope.joinSelectedNetwork = function (networkId, joinId) {
2400        var onSuccess = function () {
2401            $log.debug('addNetwork', 'Success');
2402            Dialogs.alert('You are now a member!');
2403            session.refresh();
2404        };
2405        var onFault = function (error) {
2406            $log.debug('addNetwork', 'Error', error);
2407            session.refresh();
2408            if (error.data.name && error.data.name.match('Exists'))
2409                Dialogs.alert('You are already a member!');
2410            else
2411                Dialogs.alert('You were not added.');
2412        };
2413        if ($scope.isPublic) {
2414            session.user
2415                .post('networks', {
2416                network: networkId,
2417            })
2418                .then(onSuccess, onFault);
2419        }
2420        else {
2421            session.user
2422                .post('networks', {
2423                network: networkId,
2424                joinId: joinId,
2425            })
2426                .then(onSuccess, onFault);
2427        }
2428    };
2429    function addUserToNetwork(networkId) {
2430        $scope.user
2431            .post('networks', {
2432            network: networkId,
2433        })
2434            .then(function (network) {
2435            Dialogs.alert({
2436                unsafeMessage: 'You have joined the <var networkName>' +
2437                    $sanitize(network.name) +
2438                    " network! Check out Step 5 for program details and the 'Complete' message for what to do next!",
2439            });
2440            updateNetworks();
2441            session.refresh();
2442        });
2443    }
2444    $scope.removeNetwork = function (network) {
2445        var message = 'Are you sure you want to leave the <var networkName>' +
2446            _.escape(network.name) +
2447            '</var> network?';
2448        Dialogs.confirm({
2449            unsafeMessage: message,
2450            callback: function (val) {
2451                if (val)
2452                    $scope.user
2453                        .one('networks', network._id)
2454                        .remove()
2455                        .then(function () {
2456                        updateNetworks();
2457                        session.refresh();
2458                    });
2459            },
2460        });
2461    };
2462    $scope.$watch('newNetwork', function (value) {
2463        if (value) {
2464            addUserToNetwork(value);
2465            $scope.newNetwork = undefined;
2466        }
2467    });
2468    $scope.randomNumber = Math.floor(Math.random() * 999 + 1);
2469});
2470appControllers.controller('dashboardNetworkListWidget', function ($scope, vNetworks, Restangular) {
2471    $scope.$watch('session.user', function (user) {
2472        if (user) {
2473            $scope.user = Restangular.copy(user);
2474            updateNetworks();
2475        }
2476        else {
2477            $scope.user = null;
2478        }
2479    });
2480    $scope.userNetworks = [];
2481    function updateNetworks() {
2482        $scope.user.getList('networks').then(function (userNetworks) {
2483            $scope.userNetworks = userNetworks.map(function (userNetwork) {
2484                return {
2485                    name: userNetwork.name,
2486                    hiddenFromUsers: userNetwork.hiddenFromUsers,
2487                    logoURL: userNetwork.logoURL,
2488                };
2489            });
2490        });
2491    }
2492});
2493appControllers.controller('solanoFormExtras', function ($scope, vNetworks) {
2494    $scope.firstCheckboxSet = [
2495        {
2496            checkboxesOptions: {
2497                values: ['Work/School', 'Shopping/Errands', 'Social/Recreation'],
2498                otherInput: true,
2499            },
2500            values: ['Work/School', 'Shopping/Errands', 'Social/Recreation'],
2501            fieldKey: 'purpose',
2502            fieldLabel: 'What is the purpose of your regular trip through the State Route 37 Corridor? Select all that apply if you regularly commute through the corridor for multiple purposes',
2503            fieldName: 'Purpose',
2504            fieldType: 'checkboxes',
2505        },
2506        {
2507            checkboxesOptions: {
2508                values: ['Car (alone)', 'Carpool', 'Vanpool', 'Bus/Shuttle'],
2509                otherInput: true,
2510            },
2511            fieldKey: 'mode',
2512            fieldLabel: 'How do you usually travel on the State Route 37 Corridor? Select all that apply',
2513            fieldName: 'mode',
2514            fieldType: 'checkboxes',
2515        },
2516    ];
2517    $scope.secondCheckboxSet = [
2518        {
2519            checkboxesOptions: {
2520                values: [
2521                    'Off-Peak Mornings (Midnight-7am)',
2522                    'Peak Mornings (7am-10am)',
2523                    'Mid-Day (10am - 3pm)',
2524                    'Peak Evenings (3pm-7pm)',
2525                    'Off-Peak Evenings (7pm-11:59pm)',
2526                ],
2527            },
2528            fieldKey: 'travel_time',
2529            fieldLabel: 'What time(s) during the day do you typically travel through the State Route 37 Corridor? More than one answer is allowed.',
2530            fieldName: 'Travel Time',
2531            fieldType: 'checkboxes',
2532            required: true,
2533        },
2534        {
2535            checkboxesOptions: {
2536                values: [
2537                    'Monday',
2538                    'Tuesday',
2539                    'Wednesday',
2540                    'Thursday',
2541                    'Friday',
2542                    'Saturday',
2543                    'Sunday',
2544                ],
2545                otherInput: false,
2546            },
2547            fieldKey: 'days_of_the_week',
2548            fieldLabel: 'Which days do you typically travel along the State Route 37 Corridor?',
2549            fieldName: 'Days of the week',
2550            fieldType: 'checkboxes',
2551            required: true,
2552        },
2553        {
2554            checkboxesOptions: {
2555                values: [
2556                    'Monday',
2557                    'Tuesday',
2558                    'Wednesday',
2559                    'Thursday',
2560                    'Friday',
2561                    'Saturday',
2562                    'Sunday',
2563                    'My telework schedule varies each week',
2564                    'I do not have the ability to telework',
2565                ],
2566            },
2567            fieldKey: 'telework',
2568            fieldLabel: 'Do you have the ability to Telework? If yes, select the day(s) in which you typically telework',
2569            fieldName: 'Telework',
2570            fieldType: 'checkboxes',
2571            required: true,
2572        },
2573    ];
2574});
2575appControllers.controller('AccountEditController', function ($scope, $rootScope, $state, $sanitize, $filter, vSession, vUser, Restangular, Dialogs, vNetworks, $log, SessionUserDataService, vTriplogs, $window, AccountResolvingService, GeoJSON) {
2576    'use strict';
2577    $log = $log.getInstance('AccountEditController');
2578    $log.debug('Initialized.');
2579    $scope.sessionData = SessionUserDataService;
2580    $scope.sessionData.updateUserData();
2581    $scope.$watch('session.user', function (user) {
2582        if (user) {
2583            $scope.user = Restangular.copy(user);
2584            $scope.checkAll();
2585            updateUserNetworks();
2586            updateManagedNetworks();
2587        }
2588        else
2589            $scope.user = null;
2590    });
2591    $scope.checkAll = function () {
2592        if ($scope.user && $scope.user.emailPreferences) {
2593            $scope.selectedAll = Object.values($scope.user.emailPreferences).every(Boolean);
2594        }
2595        if ($('#subscribeToAll').prop('checked') !== $scope.selectedAll) {
2596            $('#subscribeToAll').prop('checked', $scope.selectedAll);
2597        }
2598    };
2599    $scope.setAllChecked = function (value) {
2600        Object.keys($scope.user.emailPreferences).forEach(function (key) {
2601            $scope.user.emailPreferences[key] = value;
2602        });
2603    };
2604    $scope.userNetworks = [];
2605    function updateManagedNetworks() {
2606        session.user.getList('managednetworks').then(function (nets) {
2607            $scope.managedNetworks = nets;
2608        });
2609    }
2610    function updateUserNetworks() {
2611        $scope.user.getList('networks').then(function (networks) {
2612            $scope.userNetworks = networks;
2613            vNetworks.getList().then(function (networks) {
2614                networks = _.sortBy(networks, 'name');
2615                var networkData = [];
2616                _.forEach(networks, function (net) {
2617                    if (!_.includes(_.map($scope.userNetworks, '_id'), net._id) &&
2618                        net.isPublic &&
2619                        !net.hiddenFromUsers)
2620                        networkData.push({
2621                            id: net._id,
2622                            text: net.name,
2623                            network: net,
2624                        });
2625                });
2626                $('#networkSearch')
2627                    .off('change')
2628                    .select2({
2629                    dropdownCssClass: 'set_ddl_size',
2630                    data: networkData,
2631                    formatResult: function (net) {
2632                        var networkRendererHTML = "<div role='region' aria-label='" +
2633                            _.escape(net.network.name) +
2634                            ": Select to join'><p>" +
2635                            '<b><var networkName>' +
2636                            _.escape(net.network.name) +
2637                            '</var></b> ' +
2638                            '<small>(' +
2639                            net.network.type +
2640                            ')</small>' +
2641                            '</p></div>';
2642                        var parentNetworkNames = _.map(net.network.ancestors, 'name');
2643                        if (parentNetworkNames.length > 0) {
2644                            networkRendererHTML +=
2645                                "<p><small class='text-muted'><i><b isolate>Parent Network:</b><span notranslate> " +
2646                                    _.escape(parentNetworkNames.join(', ')) +
2647                                    '</span></i></small></p>';
2648                        }
2649                        if (net.network.description) {
2650                            networkRendererHTML +=
2651                                '<p><i><var description>' +
2652                                    $sanitize($filter('markdownToHTML')(net.network.description)) +
2653                                    '</var></i></p><hr />';
2654                        }
2655                        if (!net.network.description) {
2656                            networkRendererHTML += '<hr />';
2657                        }
2658                        return networkRendererHTML;
2659                    },
2660                })
2661                    .on('change', function (e) {
2662                    $(e.target).val('');
2663                    if (e.val)
2664                        $scope.$apply(function () {
2665                            addUserToNetwork(e.val);
2666                        });
2667                });
2668            });
2669        });
2670    }
2671    function addUserToNetwork(networkId) {
2672        $scope.user
2673            .post('networks', {
2674            network: networkId,
2675        })
2676            .then(function (network) {
2677            session.refresh();
2678            Dialogs.alert({
2679                unsafeMessage: 'You have joined the ' +
2680                    network.type +
2681                    " network <var networkName>'" +
2682                    $sanitize(network.name) +
2683                    "'</var>",
2684            });
2685        });
2686    }
2687    $scope.removeNetwork = function (network) {
2688        var message = 'Are you sure you want to leave the ' +
2689            network.type +
2690            " network <var networkName>'" +
2691            _.escape(network.name) +
2692            "'</var>?";
2693        Dialogs.confirm({
2694            unsafeMessage: message,
2695            callback: function (val) {
2696                if (val)
2697                    $scope.user
2698                        .one('networks', network._id)
2699                        .remove()
2700                        .then(function () {
2701                        session.refresh();
2702                    });
2703            },
2704        });
2705    };
2706    $scope.makePrimaryNetwork = function (network) {
2707        var message = 'Are you sure you want to make the ' +
2708            network.type +
2709            " network <var networkName>'" +
2710            _.escape(network.name) +
2711            "'</var> your primary network?";
2712        Dialogs.confirm({
2713            unsafeMessage: message,
2714            callback: function (val) {
2715                if (val)
2716                    $scope.user
2717                        .one('primary-network')
2718                        .post('', { network: network._id })
2719                        .then(function (r) {
2720                        if (r) {
2721                            $scope.user
2722                                .one('primary-network')
2723                                .get()
2724                                .then(function (network) {
2725                                $rootScope.PRIMARY_NETWORK = network;
2726                            });
2727                        }
2728                    });
2729            },
2730        });
2731    };
2732    $scope.onLocationCoordinateChange = function (data) {
2733        $scope.profileEdit.$setDirty();
2734    };
2735    $scope.$watch('newNetwork', function (value) {
2736        if (value) {
2737            addUserToNetwork(value);
2738            $scope.newNetwork = undefined;
2739        }
2740    });
2741    $scope.usualMode = undefined;
2742    vTriplogs
2743        .all('modes')
2744        .getList()
2745        .then(function (modes) {
2746        $scope.modes = modes;
2747    });
2748    $scope.formatHomeLocationAddress = GeoJSON.formatLocationAddress.bind(null, 'Home');
2749    $scope.formatWorkLocationAddress = GeoJSON.formatLocationAddress.bind(null, 'Work');
2750    $scope.displayLocationAddress = GeoJSON.pullLocationAddress;
2751    $scope.update = _.debounce(function () {
2752        $scope.user.put().then(function () {
2753            Dialogs.successToast('Your changes were saved.');
2754            vSession.refresh();
2755        }, function (err) {
2756            err.type = 'POST';
2757            AccountResolvingService.handleError(err);
2758        });
2759    }, 250);
2760    $scope.removeAccount = function () {
2761        Dialogs.confirm({
2762            message: 'Are you absolutely sure  you want to remove your account?',
2763            callback: function (remove) {
2764                if (remove) {
2765                    $scope.user.remove().then(function () {
2766                        vSession.refresh();
2767                        $state.go('home');
2768                    });
2769                }
2770            },
2771        });
2772    };
2773    $scope.reloadPage = function () {
2774        $window.location.reload();
2775    };
2776    $scope.changePassword = function (newPassword, currentPassword) {
2777        if (newPassword.length < 6)
2778            return Dialogs.alert('Your new password must contain at least 6 characters. Please try again.');
2779        if (newPassword) {
2780            $scope.user.setPassword(newPassword, currentPassword).then(function () {
2781                vSession.refresh();
2782                return Dialogs.alert({
2783                    message: 'Your password was successfully changed.',
2784                    callback: $scope.reloadPage,
2785                });
2786            }, function (err) {
2787                return Dialogs.alert({
2788                    message: 'There was a problem changing your password. Please try again.',
2789                    callback: $scope.reloadPage,
2790                });
2791            });
2792        }
2793    };
2794    $scope.fromUrl = $rootScope.fromUrl;
2795    $scope.browser = kendo.support.browser;
2796    $scope.mobileOS = kendo.support.mobileOS;
2797});
2798appControllers.controller('PasswordResetController', function ($scope, $rootScope, vUser, vSession, vPasswordReset, $stateParams, $state, $log, Dialogs) {
2799    'use strict';
2800    $log = $log.getInstance('PasswordResetController');
2801    $scope.token = $stateParams.token || $stateParams.migrate || null;
2802    $scope.validToken;
2803    $scope.$watch('token', function (token) {
2804        if (token)
2805            validateToken(token);
2806        $stateParams.token = null;
2807    });
2808    $scope.user = {};
2809    if ($rootScope.emailInput)
2810        $scope.user.email = $rootScope.emailInput;
2811    $scope.$watch('user.email', function (emailInput) {
2812        $rootScope.emailInput = $rootScope.EMAIL_REGEXP.test(emailInput)
2813            ? emailInput
2814            : null;
2815    });
2816    function validateToken(token) {
2817        vPasswordReset.validateResetToken(token).then(function () {
2818            $scope.validToken = token;
2819        }, function () {
2820            Dialogs.alert('Your reset token is invalid. Please try again.');
2821            $scope.token = null;
2822        });
2823    }
2824    $scope.requestPasswordReset = function (email) {
2825        vPasswordReset.requestPasswordReset(email).then(function () {
2826            Dialogs.alert({
2827                unsafeMessage: 'We sent a password reset link to <var email>' +
2828                    _.escape(email) +
2829                    '</var>, please check your email.',
2830            });
2831            close();
2832        }, function (err) {
2833            Dialogs.alert({
2834                unsafeMessage: 'We could not find a user for <var email>' +
2835                    _.escape(email) +
2836                    '</var>, please check your email address and try again.',
2837            });
2838        });
2839    };
2840    $scope.resetPassword = function (token, password) {
2841        if (password.length < 6)
2842            return Dialogs.alert('Your new password must contain at least 6 characters. Please try again.');
2843        vPasswordReset.resetPassword(token, password).then(function () {
2844            Dialogs.alert('Your password has been updated. Welcome back!');
2845            close();
2846        }, function () {
2847            Dialogs.alert('We encountered a problem resetting your password, please try again.');
2848            $scope.token = $scope.validToken = undefined;
2849        });
2850    };
2851    function close() {
2852        $rootScope.globalModalHide();
2853        $state.go('home', {});
2854    }
2855});
2856appControllers.controller('AccountStatsController', function ($scope, $timeout, CONFIG, _, vTriplogreports, $filter, $log, SessionUserDataService, vUser, Dialogs, vSession, KendoReport, Restangular, quicklogService) {
2857    $log = $log.getInstance('AccountStatsController');
2858    $scope.sessionData = SessionUserDataService;
2859    var userId = $scope.userId || vSession.user._id;
2860    $scope.isStatButtonVisible = function () {
2861        if (!_.isUndefined($scope.showStatsButton)) {
2862            return $scope.showStatsButton;
2863        }
2864        else {
2865            return ($scope.dashboard.id !== 'triplog' && CONFIG.dashboards.triplog.inMenu);
2866        }
2867    };
2868    $scope.selectOptions = [
2869        { val: 'alltime', label: 'All Time', default: true },
2870        {
2871            val: 'thismonth',
2872            startDate: moment().startOf('month'),
2873            endDate: moment().endOf('month'),
2874            label: 'This Month',
2875        },
2876        {
2877            val: 'lastmonth',
2878            startDate: moment().subtract(1, 'months').startOf('month'),
2879            endDate: moment().subtract(1, 'months').endOf('month'),
2880            label: 'Last Month',
2881        },
2882        {
2883            val: 'thisweek',
2884            startDate: moment().subtract(1, 'weeks').startOf('day'),
2885            endDate: moment().endOf('day'),
2886            label: 'Past 7 Days',
2887        },
2888        {
2889            val: 'past30days',
2890            startDate: moment().subtract(30, 'days').startOf('day'),
2891            endDate: moment().endOf('day'),
2892            label: 'Past 30 Days',
2893        },
2894        {
2895            val: 'thisyear',
2896            startDate: moment().subtract(1, 'year').startOf('day'),
2897            endDate: moment().endOf('day'),
2898            label: 'Past 12 Months',
2899        },
2900    ];
2901    for (var i = 3; i >= 0; i--) {
2902        var quarterMoment = moment().startOf('quarter').subtract(i, 'quarter');
2903        $scope.selectOptions.push({
2904            val: 'quarter' + quarterMoment.format('Q_YY'),
2905            startDate: quarterMoment,
2906            endDate: moment(quarterMoment).add(1, 'quarter').subtract(1, 'hour'),
2907            label: 'Quarter ' + quarterMoment.format('Q YYYY'),
2908        });
2909    }
2910    console.log($scope.selectOptions);
2911    $scope.refresh = _.debounce(_refresh, 500);
2912    $scope.dateSelect = $scope.selectOptions[0];
2913    $scope.$watch('sessionData.triplogReport.trips', $scope.refresh);
2914    $scope.$watch('dateSelect', $scope.refresh);
2915    quicklogService.subscribeToRemoteChanges($scope, _.debounce($scope.refresh, 1500));
2916    $scope.updateData = function (range) {
2917        if (range) {
2918            if (range.startDate) {
2919                updateModeshare(range);
2920                vTriplogreports
2921                    .one('user', userId)
2922                    .get({
2923                    startDate: range.startDate.format(),
2924                    endDate: range.endDate.format(),
2925                })
2926                    .then(function (stats) {
2927                    $scope.stats = stats;
2928                });
2929            }
2930            else {
2931                updateModeshare();
2932                vTriplogreports
2933                    .one('user', userId)
2934                    .get()
2935                    .then(function (stats) {
2936                    $scope.stats = stats;
2937                });
2938            }
2939        }
2940    };
2941    function _refresh() {
2942        $timeout(function () {
2943            $scope.updateData($scope.dateSelect);
2944        });
2945    }
2946    var reportSvc = new KendoReport('users/' + userId + '/triplogs/report');
2947    reportSvc.get();
2948    $scope.reportSvc = reportSvc;
2949    $scope.loadingModeshare = false;
2950    function updateModeshare(dateRange) {
2951        var filterString = '';
2952        if (dateRange && dateRange.startDate) {
2953            var dateFormat = 'YYYY-MM-DD';
2954            var query = {};
2955            query.startDate = dateRange.startDate.format(dateFormat);
2956            query.endDate = dateRange.endDate.format(dateFormat);
2957            filterString = '?' + $.param(query);
2958        }
2959        $scope.loadingModeshare = true;
2960        Restangular.oneUrl('modeshare', '/api/v1/users/' + userId + '/triplogs/modeshare' + filterString)
2961            .get()
2962            .then(function (modeshare) {
2963            modeshare.csvUrl =
2964                '/api/v1/users/' +
2965                    userId +
2966                    '/triplogs/modeshare.csv' +
2967                    filterString;
2968            $scope.modeshare = modeshare;
2969            $scope.loadingModeshare = false;
2970        }, function () {
2971            $scope.loadingModeshare = false;
2972        });
2973    }
2974});
2975appControllers.controller('AdminDashboardController', function ($scope, $log, vSession, vUser, vNetworks, vTriplogs, vTripsearches, vTripplans, Dialogs, $http) {
2976    'use strict';
2977    $log = $log.getInstance('AdminDashboardController');
2978    $log.debug('loaded.');
2979    $scope.get = function () {
2980        $http.get('/api/v1/admin/reports/dashboard').then(function (data) {
2981            console.error(data);
2982            $scope.$applyAsync(function () {
2983                $scope.report = data.data;
2984                console.error($scope.report);
2985            });
2986        });
2987    };
2988    $scope.get();
2989});
2990appControllers.controller('AdminUserListController', function ($scope, $state, $log, vSession, vUser, vTriplogs, Dialogs, $http, NgTableParams) {
2991    'use strict';
2992    $log = $log.getInstance('AdminUserListController');
2993    $log.debug('loaded.');
2994    function paramsToUrlParams(params) {
2995        var p = params;
2996        var newParams = {};
2997        newParams.page = p.page;
2998        newParams.count = p.count;
2999        newParams.query = p.filter;
3000        newParams.sort = {};
3001        _.forIn(p.sorting, function (val, key) {
3002            newParams.sort[key] = val === 'asc' ? 1 : -1;
3003        });
3004        newParams.query = JSON.stringify(newParams.query);
3005        newParams.sort = JSON.stringify(newParams.sort);
3006        if ($scope.statQuery)
3007            newParams.statQuery = JSON.stringify($scope.statQuery);
3008        return newParams;
3009    }
3010    $scope.getStatQueryString = function () {
3011        if ($scope.statQuery)
3012            return 'statQuery=' + JSON.stringify($scope.statQuery);
3013        else
3014            return '';
3015    };
3016    $scope.tableParams = new NgTableParams({
3017        page: 1,
3018        count: 10,
3019        sorting: {
3020            lastName: 'asc',
3021        },
3022    }, {
3023        total: 0,
3024        getData: function (params) {
3025            var urlParams = paramsToUrlParams(params._params);
3026            return $http
3027                .get('/api/v1/admin/reports/users', {
3028                params: urlParams,
3029            })
3030                .then(function (data) {
3031                data = data.data;
3032                params.total(data.count);
3033                return data.results;
3034            });
3035        },
3036    });
3037    $scope.reload = function (option) {
3038        if (option === 'clearDates')
3039            $scope.statQuery.startDate = $scope.statQuery.endDate = null;
3040        $scope.tableParams.reload();
3041    };
3042    $scope.remove = function (user) {
3043        Dialogs.confirm({
3044            unsafeMessage: 'Are you absolutely sure you want to remove <var userName>' +
3045                _.escape(user.firstName) +
3046                ' ' +
3047                _.escape(user.lastName) +
3048                '</var> ?',
3049            callback: function (value) {
3050                if (value) {
3051                    vUser
3052                        .one(user._id)
3053                        .remove()
3054                        .then(function () {
3055                        $scope.reload();
3056                        Dialogs.alert('The user was deleted.');
3057                    }, function () {
3058                        $scope.reload();
3059                        Dialogs.alert('There was a problem deleting the user.');
3060                    });
3061                }
3062            },
3063        });
3064    };
3065    $scope.create = function () {
3066        $state.go('admin.users.detail', {
3067            userId: 'new',
3068        });
3069    };
3070});
3071appControllers.controller('AdminUserDetailController', function ($scope, $log, vSession, vUser, vNetworks, vTripplans, vTriplogs, userId, $state, Dialogs, $http, $timeout, KendoReport, Restangular, GeoJSON, vAccountActivation, vPasswordReset) {
3072    'use strict';
3073    $log = $log.getInstance('AdminUserDetailController');
3074    $scope.setTab = function (tab) {
3075        $scope.visibleTab = tab;
3076        $state.params.tab = tab;
3077        $state.transitionTo($state.current, $state.params, { notify: false });
3078    };
3079    $scope.setTab($state.params.tab || 'basic');
3080    $log.debug('loaded.');
3081    $scope._ = _;
3082    $scope.isNew = userId === 'new';
3083    $scope.astroAllowAdminTogglePlanning =
3084        CONFIG.integrations.astroAllowAdminTogglePlanning ||
3085            vSession.user.email.match('rideamigos.com');
3086    if (!$scope.isNew) {
3087        $http.get('/api/v1/triplogreports/user/' + userId).then(function (data) {
3088            if (data.data)
3089                $scope.report = data.data;
3090        });
3091    }
3092    $scope.carpoolMessagesReceived = [];
3093    $scope.carpoolMessagesReceivedCount = null;
3094    var destroySumWatch = $scope.$watchCollection('user.tripPlans', function (tripPlans) {
3095        var sum = null;
3096        if (tripPlans && tripPlans.length) {
3097            angular.forEach(tripPlans, function (plan) {
3098                sum += plan.messageCount;
3099            });
3100            $scope.carpoolMessagesReceivedCount = sum;
3101            destroySumWatch();
3102        }
3103    });
3104    $scope.formatHomeLocationAddress = GeoJSON.formatLocationAddress.bind(null, 'Home');
3105    $scope.formatWorkLocationAddress = GeoJSON.formatLocationAddress.bind(null, 'Work');
3106    $scope.displayLocationAddress = GeoJSON.pullLocationAddress;
3107    $scope.highlightID = function (thisID, thisClassName) {
3108        var thisClass = thisClassName || 'highlight';
3109        var thisElement = angular.element('#' + thisID);
3110        if (thisElement.length) {
3111            thisElement.addClass('highlight');
3112            $timeout(function () {
3113                thisElement.removeClass(thisClass);
3114            }, 3000);
3115        }
3116    };
3117    $scope.addNetwork = function (network) {
3118        if (!network || !network.length)
3119            return;
3120        var message = 'Are you sure you want to add <var userName>' +
3121            _.escape($scope.user.firstName) +
3122            ' ' +
3123            _.escape($scope.user.lastName) +
3124            '</var> as a member to this network?';
3125        var onConfirmResult = function (confirmed) {
3126            var onSuccess = function () {
3127                $log.debug('addNetwork', 'Success');
3128                Dialogs.alert('Member was added!');
3129                $scope.reload();
3130            };
3131            var onFault = function (error) {
3132                $log.debug('addNetwork', 'Error', error);
3133                if (error.data.name && error.data.name.match('Exists'))
3134                    Dialogs.alert('The user was already a member!');
3135                else
3136                    Dialogs.alert('The user was not added.');
3137            };
3138            if (confirmed)
3139                vNetworks
3140                    .one(network)
3141                    .post('members', {
3142                    member: $scope.user._id,
3143                })
3144                    .then(onSuccess, onFault);
3145            $scope.newNetwork = undefined;
3146        };
3147        Dialogs.confirm({
3148            unsafeMessage: message,
3149            callback: onConfirmResult,
3150        });
3151    };
3152    $scope.addPrimaryNetwork = function (network) {
3153        var message = 'Are you sure you want to make the ' +
3154            network.type +
3155            " network <var networkName>'" +
3156            _.escape(network.name) +
3157            "'</var> this user's primary network?";
3158        Dialogs.confirm({
3159            unsafeMessage: message,
3160            callback: function (val) {
3161                if (val) {
3162                    $scope.user
3163                        .one('primary-network')
3164                        .post('', { network: network._id })
3165                        .then(function (r) {
3166                        if (r) {
3167                            $scope.user.primaryNetwork = network._id;
3168                        }
3169                    });
3170                }
3171            },
3172        });
3173    };
3174    $scope.removeNetwork = function (network) {
3175        var onConfirmResult = function (confirmed) {
3176            var onSuccess = function () {
3177                $log.debug('removeNetwork', 'Success');
3178                Dialogs.alert('Member was removed!');
3179                $scope.reload();
3180            };
3181            var onFault = function (error) {
3182                $log.debug('removeNetwork', 'Error', error);
3183                Dialogs.alert('The user was not removed.');
3184            };
3185            if (confirmed)
3186                vNetworks
3187                    .one(network)
3188                    .one('members', $scope.user._id)
3189                    .remove()
3190                    .then(onSuccess, onFault);
3191        };
3192        Dialogs.confirm({
3193            message: "Are you sure you want to remove this user's member role?",
3194            callback: onConfirmResult,
3195        });
3196    };
3197    $scope.removeManagedNetwork = function (network) {
3198        var onConfirmResult = function (confirmed) {
3199            var onSuccess = function () {
3200                $log.debug('removeManagedNetwork', 'Success');
3201                Dialogs.alert('Manager was removed!');
3202                $scope.reload();
3203            };
3204            var onFault = function (error) {
3205                $log.debug('removeManagedNetwork', 'Error', error);
3206                Dialogs.alert('The user was not removed.');
3207            };
3208            if (confirmed)
3209                vNetworks
3210                    .one(network)
3211                    .one('managers', $scope.user._id)
3212                    .remove()
3213                    .then(onSuccess, onFault);
3214        };
3215        Dialogs.confirm({
3216            message: "Are you sure you want to remove this user's manager role?",
3217            callback: onConfirmResult,
3218        });
3219    };
3220    $scope.addManagedNetwork = function (network) {
3221        if (!network || !network.length)
3222            return;
3223        var onConfirmResult = function (confirmed) {
3224            var onSuccess = function () {
3225                $log.debug('addManagedNetwork', 'Success');
3226                Dialogs.alert('Manager was added!');
3227                $scope.reload();
3228            };
3229            var onFault = function (error) {
3230                $log.debug('addManagedNetwork', 'Error', error);
3231                if (error.data.name && error.data.name.match('Exists')) {
3232                    Dialogs.alert('The user was already a manager!');
3233                }
3234                else {
3235                    Dialogs.alert('The user was not added.');
3236                }
3237            };
3238            if (confirmed) {
3239                vNetworks
3240                    .one(network)
3241                    .post('managers', {
3242                    manager: $scope.user._id,
3243                })
3244                    .then(onSuccess, onFault);
3245            }
3246            $scope.newManagedNetwork = undefined;
3247        };
3248        Dialogs.confirm({
3249            unsafeMessage: 'Are you sure you want to add <var userName>' +
3250                _.escape($scope.user.firstName) +
3251                ' ' +
3252                _.escape($scope.user.lastName) +
3253                '</var> as a Manager to this network?',
3254            callback: onConfirmResult,
3255        });
3256    };
3257    $scope.addTripplan = function () {
3258        $scope.tripplanEdit = null;
3259        $log.debug('addTripplan', 'NEW');
3260        var GeoJsonPoint = {
3261            type: 'Point',
3262            coordinates: [0, 0],
3263        };
3264        var tripplan = {
3265            from: { label: 'Home', lat: 0, lng: 0 },
3266            to: { label: 'Work', lat: 0, lng: 0 },
3267        };
3268        var onCreateSuccess = function (tripplan) {
3269            $log.debug('addTripplan', 'NEW', 'SUCCESS', tripplan);
3270            tripplan.from = { label: null, lat: null, lng: null };
3271            tripplan.to = { label: null, lat: null, lng: null };
3272            $scope.tripplanEdit = tripplan;
3273        };
3274        var onCreateFault = function (error) {
3275            $log.error('addTripplan', 'NEW', 'ERROR', error);
3276            Dialogs.alert('Oops, we encountered a problem creating a new trip.');
3277        };
3278        Restangular.one('users', $scope.user._id)
3279            .post('tripplans', tripplan)
3280            .then(onCreateSuccess, onCreateFault);
3281    };
3282    $scope.$on('tripplanEditClose', function () {
3283        $scope.tripplanEdit = null;
3284        $scope.reload();
3285    });
3286    $scope.editTrip = function (tripplan) {
3287        $scope.tripplanEdit = tripplan.clone();
3288    };
3289    $scope.deleteTripplan = function (tripplan) {
3290        Restangular.one('users', $scope.user._id)
3291            .one('tripplans', tripplan._id)
3292            .remove()
3293            .then(function () {
3294            $scope.reload();
3295        }, function () { });
3296    };
3297    $scope.requestEmailValidation = function (email) {
3298        if ($scope.user.locked)
3299            return;
3300        vAccountActivation.requestAccountActivation(email).then(function () {
3301            Dialogs.alert({
3302                unsafeMessage: 'We sent a email confirmation link to <var email>' +
3303                    _.escape(email) +
3304                    '</var>, please have this user check their email.',
3305            });
3306            close();
3307        }, function (err) {
3308            Dialogs.alert({
3309                unsafeMessage: 'We could not find a user for <var email>' +
3310                    _.escape(email) +
3311                    '</var>, please check the email address and try again.',
3312            });
3313        });
3314    };
3315    $scope.requestPasswordReset = function (email) {
3316        if ($scope.user.locked)
3317            return;
3318        vPasswordReset.requestPasswordReset(email).then(function () {
3319            Dialogs.alert({
3320                unsafeMessage: 'We sent a password reset link to <var email>' +
3321                    _.escape(email) +
3322                    '</var>, please have this user check their email.',
3323            });
3324            close();
3325        }, function (err) {
3326            Dialogs.alert({
3327                unsafeMessage: 'We could not find a user for <var email>' +
3328                    _.escape(email) +
3329                    '</var>, please check your email address and try again.',
3330            });
3331        });
3332    };
3333    $scope.lockUser = function () {
3334        Dialogs.open({
3335            unsafeMessage: "\n        <p>Locking an account will remove active session(s) and disable future logins. Account will not be removed and can be reinstated at a later date.</p>\n        <p>Please confirm action below.</p>\n      ",
3336            input: "\n      <div class=\"vex-custom-field-wrapper\">\n        <label for=\"Reason\">Reason for account suspension:</label><br>\n        <div class=\"vex-custom-input-wrapper\">\n          <input type=\"text\" id=\"reason\" name=\"reason\" value=\"suspicious activity\">\n        </div>\n      </div>",
3337            callback: function (lock) {
3338                if (lock) {
3339                    $scope.user.lockAccount(lock).then(function (user) {
3340                        Dialogs.successToast('Account Locked!');
3341                        $scope.user.locked = true;
3342                        if ($scope.userForm)
3343                            $scope.userForm.$setPristine(true);
3344                    }, function (_err) {
3345                        Dialogs.alert('There was a problem locking this user.');
3346                    });
3347                }
3348            },
3349        });
3350    };
3351    $scope.unlockUser = function () {
3352        return __awaiter(this, void 0, void 0, function () {
3353            var followUpAction;
3354            return __generator(this, function (_a) {
3355                followUpAction = function (email) {
3356                    Dialogs.successToast('Account Unlocked!');
3357                    return Dialogs.confirm({
3358                        message: 'Send a password reset email to this user?',
3359                        callback: function (send) {
3360                            if (send) {
3361                                vPasswordReset
3362                                    .requestPasswordReset(email)
3363                                    .then(function () { return close(); })
3364                                    .catch(function () {
3365                                    Dialogs.alert('There was a problem sending the password reset email. Please contact user directly.');
3366                                });
3367                            }
3368                        },
3369                    });
3370                };
3371                return [2, Dialogs.confirm({
3372                        message: 'Are you sure you want to unlock this account?',
3373                        callback: function (unlock) {
3374                            return __awaiter(this, void 0, void 0, function () {
3375                                return __generator(this, function (_a) {
3376                                    switch (_a.label) {
3377                                        case 0:
3378                                            if (!unlock) return [3, 2];
3379                                            return [4, $scope.user
3380                                                    .unlockAccount()
3381                                                    .then(function (user) {
3382                                                    $scope.user.locked = false;
3383                                                    if ($scope.userForm)
3384                                                        $scope.userForm.$setPristine(true);
3385                                                    return user.email;
3386                                                })
3387                                                    .catch(function () {
3388                                                    return Dialogs.alert('There was a problem unlocking this user.');
3389                                                })
3390                                                    .then(followUpAction)];
3391                                        case 1:
3392                                            _a.sent();
3393                                            _a.label = 2;
3394                                        case 2: return [2];
3395                                    }
3396                                });
3397                            });
3398                        },
3399                    })];
3400            });
3401        });
3402    };
3403    $scope.handleMoreActionRequest = function (type) {
3404        if (type === 'lock') {
3405            $scope.lockUser();
3406        }
3407        else {
3408            $scope.resetPassword();
3409        }
3410    };
3411    $scope.resetPassword = function () {
3412        Dialogs.prompt({
3413            label: 'Enter a new password.',
3414            placeholder: 'new password',
3415            callback: function (newPassword) {
3416                if (newPassword && newPassword.length >= 6) {
3417                    $scope.user.setPassword(newPassword).then(function () {
3418                        Dialogs.alert('The password was successfully changed.');
3419                    }, function (err) {
3420                        Dialogs.alert('There was a problem changing the password.');
3421                    });
3422                }
3423                else {
3424                    Dialogs.alert('Your password must be at least 6 characters.  Please try again.');
3425                }
3426            },
3427        });
3428    };
3429    $scope.cancel = function () {
3430        $state.go('admin.users.list');
3431    };
3432    $scope.reload = function () {
3433        if ($scope.isNew) {
3434            $scope.user = { usualSchedule: { times: ['', ''] } };
3435            vNetworks.getList().then(function (networks) {
3436                $scope.networks = networks;
3437            });
3438        }
3439        else {
3440            vUser.get(userId).then(function (user) {
3441                $scope.user = user;
3442                if ($scope.user.appSettings)
3443                    $scope.user.userAppSettings = $scope.user.appSettings;
3444                $scope.originalUser = user.clone();
3445            });
3446            vUser
3447                .one(userId)
3448                .getList('networks')
3449                .then(function (networks) {
3450                $scope.userNetworks = networks;
3451            });
3452            vUser
3453                .one(userId)
3454                .getList('managedNetworks')
3455                .then(function (managedNetworks) {
3456                $scope.userManagedNetworks = managedNetworks;
3457            });
3458            vUser
3459                .one(userId)
3460                .getList('triplogs')
3461                .then(function (triplogs) {
3462                $scope.userTriplogs = triplogs;
3463            });
3464            vUser
3465                .one(userId)
3466                .getList('tripplans')
3467                .then(function (tripplans) {
3468                $scope.userTripPlans = tripplans;
3469            });
3470            vUser
3471                .one(userId)
3472                .getList('tripsearches')
3473                .then(function (tripsearches) {
3474                $scope.userTripSearches = tripsearches;
3475            });
3476            vUser
3477                .one(userId)
3478                .getList('carpoolmessages')
3479                .then(function (carpoolmessages) {
3480                $scope.userCarpoolMessages = carpoolmessages;
3481            });
3482            vUser
3483                .one(userId)
3484                .getList('vanpools')
3485                .then(function (vanpools) {
3486                $scope.userVanpools = vanpools;
3487            });
3488            vNetworks.getList().then(function (networks) {
3489                $scope.networks = networks;
3490            });
3491            var reportSvc = new KendoReport('users/' + userId + '/triplogs/report');
3492            reportSvc.get();
3493            $scope.reportSvc = reportSvc;
3494        }
3495        if ($scope.userForm)
3496            $scope.userForm.$setPristine(true);
3497        $scope.today = new Date();
3498    };
3499    $scope.removeTripLog = function (triplog) {
3500        vUser
3501            .one(userId)
3502            .one('triplogs', triplog._id)
3503            .remove()
3504            .then(function () {
3505            $scope.reportSvc.dataSource.read();
3506        }, function () {
3507            Dialogs.alert('There was a problem deleting the triplog.  Please refresh this page then try again.');
3508        });
3509    };
3510    $scope.remove = function (user) {
3511        Dialogs.confirm({
3512            unsafeMessage: 'Are you absolutely sure you want to remove <var userName>' +
3513                _.escape(user.firstName + ' ' + user.lastName) +
3514                '</var> ?',
3515            callback: function (value) {
3516                if (value) {
3517                    user.remove().then(function () {
3518                        Dialogs.alert('The user was deleted.');
3519                        $scope.cancel();
3520                    }, function () {
3521                        Dialogs.alert('There was a problem deleting the user.');
3522                        $scope.cancel();
3523                    });
3524                }
3525            },
3526        });
3527    };
3528    $scope.usualMode = undefined;
3529    vTriplogs
3530        .all('modes')
3531        .getList()
3532        .then(function (modes) {
3533        $scope.modes = modes;
3534    });
3535    $scope.save = function () {
3536        if ($scope.isNew) {
3537            $scope.user.source = 'Admin-Created';
3538            vUser.post($scope.user).then(function (newUser) {
3539                $state.go('admin.users.detail', {
3540                    userId: newUser._id,
3541                });
3542                Dialogs.alert('The user was created.');
3543            }, function (err) {
3544                $log.debug(err);
3545                Dialogs.alert('There was a problem creating the user.');
3546            });
3547        }
3548        else {
3549            $scope.user.put().then(function (savedUser) {
3550                $scope.reload();
3551                Dialogs.alert('The user was saved.');
3552            }, function (err) {
3553                $log.debug(err);
3554                Dialogs.alert('There was a problem saving the user.');
3555            });
3556        }
3557    };
3558    $scope.reload();
3559});
3560appControllers.controller('AdminNetworkListController', function ($scope, $log, $state, vSession, vNetworks, Dialogs, $timeout, NgTableParams, $http) {
3561    'use strict';
3562    $log = $log.getInstance('AdminNetworkListController');
3563    $log.debug('loaded.');
3564    function paramsToUrlParams(params) {
3565        var p = params;
3566        var newParams = {};
3567        newParams.page = p.page;
3568        newParams.count = p.count;
3569        newParams.query = p.filter;
3570        newParams.sort = {};
3571        _.forIn(p.sorting, function (val, key) {
3572            newParams.sort[key] = val == 'asc' ? 1 : -1;
3573        });
3574        newParams.query = JSON.stringify(newParams.query);
3575        newParams.sort = JSON.stringify(newParams.sort);
3576        return newParams;
3577    }
3578    $scope.tableParams = new NgTableParams({
3579        page: 1,
3580        count: 10,
3581        sorting: {
3582            name: 'asc',
3583        },
3584    }, {
3585        total: 0,
3586        getData: function (params) {
3587            var urlParams = paramsToUrlParams(params._params);
3588            urlParams.joinBaseUrl = vNetworks.joinBaseUrl;
3589            urlParams.privateJoinUrlPrefix = vNetworks.privateJoinUrlPrefix;
3590            return $http
3591                .get('/api/v1/admin/reports/networks', {
3592                params: urlParams,
3593            })
3594                .then(function (data) {
3595                data = data.data;
3596                params.total(data.count);
3597                return data.results;
3598            });
3599        },
3600    });
3601    $scope.reload = function () {
3602        $scope.tableParams.reload();
3603    };
3604    $scope.remove = function (network) {
3605        Dialogs.confirm({
3606            unsafeMessage: 'Are you absolutely sure you want to remove the network: <var networkName>' +
3607                _.escape(network.name) +
3608                '</var>?',
3609            callback: function (value) {
3610                if (value) {
3611                    vNetworks
3612                        .one(network._id)
3613                        .remove()
3614                        .then(function () {
3615                        Dialogs.alert('The network was deleted.');
3616                        $scope.reload();
3617                    }, function (err) {
3618                        Dialogs.alert('There was a problem deleting the network. ' +
3619                            err.data.message);
3620                        $scope.reload();
3621                    });
3622                }
3623            },
3624        });
3625    };
3626    $scope.create = function () {
3627        $state.go('admin.networks.detail', {
3628            networkId: 'new',
3629        });
3630    };
3631});
3632appControllers.controller('AdminNetworkDetailController', function ($scope, $log, $state, vSession, vUser, vNetworks, networkId, Dialogs, vTriplogreports, CONFIG) {
3633    'use strict';
3634    $log = $log.getInstance('AdminNetworkDetailController');
3635    $log.debug('loaded.');
3636    $scope.networkTypes = CONFIG.networks.types;
3637    $scope.isNew = networkId === 'new';
3638    if (!$scope.isNew) {
3639        vTriplogreports
3640            .one('network', networkId)
3641            .get()
3642            .then(function (report) {
3643            $scope.report = report;
3644        });
3645    }
3646    if (vSession.user.isAdmin) {
3647        vNetworks.getList().then(function (networks) {
3648            $scope.availableNetworks = networks;
3649        });
3650    }
3651    $scope.newManager = null;
3652    $scope.newMember = null;
3653    $scope.$watch('newManager', function (userId) {
3654        if (userId != null && userId.length) {
3655            $scope.addNetworkManager(userId);
3656        }
3657    });
3658    $scope.$watch('newMember', function (userId) {
3659        if (userId != null && userId.length) {
3660            $scope.addNetworkMember(userId);
3661        }
3662    });
3663    $scope.resetJoinUrl = function () {
3664        $log.debug('resetJoinUrl');
3665        var callback = function (confirmed) {
3666            if (confirmed) {
3667                $log.debug('resetJoinUrl', 'Confirmed!');
3668                $scope.network
3669                    .one('joinid')
3670                    .remove()
3671                    .then(function (success) {
3672                    $log.debug('resetJoinUrl', 'SUCCESS');
3673                    Dialogs.alert('The join URL has been reset.');
3674                    $scope.reload();
3675                }, function (error) {
3676                    $log.debug('resetJoinUrl', 'ERROR', error);
3677                    Dialogs.alert('There was a problem resetting the Join Url.');
3678                });
3679            }
3680        };
3681        Dialogs.confirm({
3682            message: 'Are you sure you want to change the join URL? Any users visiting the old URL will not be able to join the network.',
3683            callback: callback,
3684        });
3685    };
3686    $scope.addNetworkMember = function (userId) {
3687        var onConfirmResult = function (confirmed) {
3688            var onSuccess = function () {
3689                $log.debug('addNetworkMember', 'Success');
3690                Dialogs.alert('Member was added!');
3691                $scope.reload();
3692            };
3693            var onFault = function (error) {
3694                $log.debug('addNetworkMember', 'Error', error);
3695                if (error.data.name && error.data.name.match('Exists'))
3696                    Dialogs.alert('The user was already a member!');
3697                else
3698                    Dialogs.alert('The user was not added.');
3699            };
3700            if (confirmed)
3701                vNetworks
3702                    .one($scope.network._id)
3703                    .post('members', {
3704                    member: userId,
3705                })
3706                    .then(onSuccess, onFault);
3707            $scope.newMember = undefined;
3708        };
3709        Dialogs.confirm({
3710            message: 'Are you sure you want to add this user as a Member?',
3711            callback: onConfirmResult,
3712        });
3713    };
3714    $scope.addNetworkManager = function (userId) {
3715        var onConfirmResult = function (confirmed) {
3716            var onSuccess = function () {
3717                $log.debug('addNetworkManager', 'Success');
3718                Dialogs.alert('Manager was added!');
3719                $scope.reload();
3720            };
3721            var onFault = function (error) {
3722                $log.debug('addNetworkManager', 'Error', error);
3723                if (error.data.name && error.data.name.match('Exists'))
3724                    Dialogs.alert('The user was already a manager!');
3725                else
3726                    Dialogs.alert('The user was not added.');
3727            };
3728            if (confirmed)
3729                vNetworks
3730                    .one($scope.network._id)
3731                    .post('managers', {
3732                    manager: userId,
3733                })
3734                    .then(onSuccess, onFault);
3735            $scope.newManager = undefined;
3736        };
3737        Dialogs.confirm({
3738            message: 'Are you sure you want to add this user as a Manager?',
3739            callback: onConfirmResult,
3740        });
3741    };
3742    $scope.removeMember = function (member) {
3743        var network = $scope.network._id;
3744        var userId = member;
3745        var onConfirmResult = function (confirmed) {
3746            var onSuccess = function () {
3747                $log.debug('removeMember', 'Success');
3748                Dialogs.alert('Member was removed!');
3749                $scope.reload();
3750            };
3751            var onFault = function (error) {
3752                $log.debug('removeMember', 'Error', error);
3753                Dialogs.alert('The user was not removed.');
3754            };
3755            if (confirmed)
3756                vNetworks
3757                    .one(network)
3758                    .one('members', userId)
3759                    .remove()
3760                    .then(onSuccess, onFault);
3761        };
3762        Dialogs.confirm({
3763            message: "Are you sure you want to remove this user's member role?",
3764            callback: onConfirmResult,
3765        });
3766    };
3767    $scope.removeManager = function (manager) {
3768        var network = $scope.network._id;
3769        var userId = manager;
3770        var onConfirmResult = function (confirmed) {
3771            var onSuccess = function () {
3772                $log.debug('removeManager', 'Success');
3773                Dialogs.alert('Manager was Removed!');
3774                $scope.reload();
3775            };
3776            var onFault = function (error) {
3777                $log.debug('removeManager', 'Error', error);
3778                Dialogs.alert('The user was not removed.');
3779            };
3780            if (confirmed)
3781                vNetworks
3782                    .one(network)
3783                    .one('managers', userId)
3784                    .remove()
3785                    .then(onSuccess, onFault);
3786        };
3787        Dialogs.confirm({
3788            message: "Are you sure you want to remove this user's manager role?",
3789            callback: onConfirmResult,
3790        });
3791    };
3792    $scope.reload = function () {
3793        if ($scope.isNew) {
3794            $scope.network = {};
3795        }
3796        else {
3797            vNetworks.get(networkId).then(function (network) {
3798                $scope.originalNetwork = network.clone();
3799                $scope.network = network;
3800                network.getList('members').then(function (members) {
3801                    $scope.members = members;
3802                });
3803                network.getList('managers').then(function (managers) {
3804                    $scope.managers = managers;
3805                });
3806            });
3807        }
3808        if ($scope.networkForm)
3809            $scope.networkForm.$setPristine(true);
3810    };
3811    $scope.cancel = function () {
3812        $state.go('admin.networks.list');
3813    };
3814    $scope.save = function () {
3815        if ($scope.isNew) {
3816            vNetworks.post($scope.network).then(function (newNetwork) {
3817                $state.go('networkadmin.overview', {
3818                    network: newNetwork._id,
3819                });
3820                Dialogs.alert({
3821                    unsafeMessage: 'Network: <var networkName>' +
3822                        _.escape(newNetwork.name) +
3823                        '</var> was created.',
3824                });
3825            }, function (err) {
3826                Dialogs.alert('There was a problem creating your network.');
3827                $log.debug('Problem creating', err);
3828            });
3829        }
3830        else {
3831            $scope.network.put().then(function (savedNetwork) {
3832                $scope.network = savedNetwork;
3833                Dialogs.alert('Your changes were saved.');
3834                $scope.reload();
3835            }, function (err) {
3836                Dialogs.alert('There was a problem saving your network.');
3837                $log.debug('Problem Updating', err);
3838            });
3839        }
3840    };
3841    $scope.remove = function (network) {
3842        Dialogs.confirm({
3843            unsafeMessage: 'Are you absolutely sure you want to remove the network: <var networkName>' +
3844                _.escape(network.name) +
3845                '</var>?',
3846            callback: function (value) {
3847                if (value) {
3848                    network.remove().then(function () {
3849                        $scope.cancel();
3850                        Dialogs.alert('The network was deleted.');
3851                    }, function (err) {
3852                        Dialogs.alert('There was a problem deleting the network. ' +
3853                            err.data.message);
3854                        $scope.reload();
3855                    });
3856                }
3857            },
3858        });
3859    };
3860    $scope.reload();
3861});
3862appControllers.controller('NetworkAdminNetworkDetailController', function ($scope, $log, $state, vSession, vUser, vNetworks, networkId, Dialogs, $http, CONFIG) {
3863    'use strict';
3864    $log = $log.getInstance('NetworkAdminNetworkDetailController');
3865    $log.debug('loaded.');
3866    $scope.networkTypes = CONFIG.networks.types;
3867    $scope.isNew = networkId === 'new';
3868    if (!$scope.isNew) {
3869        $http
3870            .get('/api/v1/triplogreports/network/' + networkId)
3871            .then(function (data) {
3872            if (data.data)
3873                $scope.report = data.data;
3874        });
3875    }
3876    $scope.newManager = null;
3877    $scope.$watch('newManager', function (userId) {
3878        if (userId != null && userId.length) {
3879            $scope.addNetworkManager(userId);
3880        }
3881    });
3882    $scope.resetJoinUrl = function () {
3883        $log.debug('resetJoinUrl');
3884        var callback = function (confirmed) {
3885            if (confirmed) {
3886                $log.debug('resetJoinUrl', 'Confirmed!');
3887                $scope.network
3888                    .one('joinid')
3889                    .remove()
3890                    .then(function (success) {
3891                    $log.debug('resetJoinUrl', 'SUCCESS');
3892                    Dialogs.alert('The join URL has been reset.');
3893                    $scope.reload();
3894                }, function (error) {
3895                    $log.debug('resetJoinUrl', 'ERROR', error);
3896                    Dialogs.alert('There was a problem resetting the Join Url.');
3897                });
3898            }
3899        };
3900        Dialogs.confirm({
3901            message: 'Are you sure you want to change the join URL? Any users visiting the old URL will not be able to join the network.',
3902            callback: callback,
3903        });
3904    };
3905    $scope.addNetworkManager = function (userId) {
3906        var onConfirmResult = function (confirmed) {
3907            var onSuccess = function () {
3908                $log.debug('addNetworkManager', 'Success');
3909                Dialogs.alert('Manager was added!');
3910                $scope.reload();
3911            };
3912            var onFault = function (error) {
3913                $log.debug('addNetworkManager', 'Error', error);
3914                if (error.data.name && error.data.name.match('Exists'))
3915                    Dialogs.alert('The user was already a manager!');
3916                else
3917                    Dialogs.alert('The user was not added.');
3918            };
3919            if (confirmed)
3920                vNetworks
3921                    .one($scope.network._id)
3922                    .post('managers', {
3923                    manager: userId,
3924                })
3925                    .then(onSuccess, onFault);
3926            $scope.newManager = undefined;
3927        };
3928        Dialogs.confirm({
3929            message: 'Are you sure you want to add this user as a Manager?',
3930            callback: onConfirmResult,
3931        });
3932    };
3933    $scope.removeMember = function (member) {
3934        var network = $scope.network._id;
3935        var userId = member;
3936        var onConfirmResult = function (confirmed) {
3937            var onSuccess = function () {
3938                $log.debug('removeMember', 'Success');
3939                Dialogs.alert('Member was removed!');
3940                $scope.reload();
3941            };
3942            var onFault = function (error) {
3943                $log.debug('removeMember', 'Error', error);
3944                Dialogs.alert('The user was not removed.');
3945            };
3946            if (confirmed)
3947                vNetworks
3948                    .one(network)
3949                    .one('members', userId)
3950                    .remove()
3951                    .then(onSuccess, onFault);
3952        };
3953        Dialogs.confirm({
3954            message: "Are you sure you want to remove this user's member role?",
3955            callback: onConfirmResult,
3956        });
3957    };
3958    $scope.removeManager = function (manager) {
3959        var network = $scope.network._id;
3960        var userId = manager;
3961        var onConfirmResult = function (confirmed) {
3962            var onSuccess = function () {
3963                $log.debug('removeManager', 'Success');
3964                Dialogs.alert('Manager was Removed!');
3965                $scope.reload();
3966            };
3967            var onFault = function (error) {
3968                $log.debug('removeManager', 'Error', error);
3969                Dialogs.alert('The user was not removed.');
3970            };
3971            if (confirmed)
3972                vNetworks
3973                    .one(network)
3974                    .one('managers', userId)
3975                    .remove()
3976                    .then(onSuccess, onFault);
3977        };
3978        Dialogs.confirm({
3979            message: "Are you sure you want to remove this user's manager role?",
3980            callback: onConfirmResult,
3981        });
3982    };
3983    $scope.reload = function () {
3984        if ($scope.isNew) {
3985            $scope.network = {};
3986        }
3987        else {
3988            vNetworks.get(networkId).then(function (network) {
3989                $scope.originalNetwork = network.clone();
3990                $scope.network = network;
3991                network.getList('members').then(function (members) {
3992                    $scope.members = members;
3993                });
3994                network.getList('managers').then(function (managers) {
3995                    $scope.managers = managers;
3996                });
3997            });
3998        }
3999        if ($scope.networkForm)
4000            $scope.networkForm.$setPristine(true);
4001    };
4002    $scope.cancel = function () {
4003        $state.go('networkadmin', { networkId: networkId });
4004    };
4005    $scope.save = function () {
4006        $scope.network.put().then(function (savedNetwork) {
4007            $scope.network = savedNetwork;
4008            Dialogs.alert('Your changes were saved.');
4009            $scope.reload();
4010        }, function (err) {
4011            Dialogs.alert('There was a problem saving your network.');
4012            $log.debug('Problem Updating', err);
4013        });
4014    };
4015    $scope.reload();
4016});
4017appControllers.controller('NetworkAdminUserDetailController', function ($scope, $log, vSession, vUser, vNetworks, userId, networkId, $state, Dialogs, $http) {
4018    'use strict';
4019    $log = $log.getInstance('NetworkAdminUserDetailController');
4020    $log.debug('loaded.');
4021    $scope.networkId = networkId;
4022    $scope.reload = function () {
4023        $http.get('/api/v1/triplogreports/user/' + userId).then(function (data) {
4024            if (data.data)
4025                $scope.report = data.data;
4026        });
4027        $http
4028            .get('/api/v1/networks/' + networkId + '/members/' + userId)
4029            .then(function (data) {
4030            $scope.user = data.data;
4031        });
4032    };
4033    $scope.reload();
4034});
4035appControllers.controller('TripSearchCardController', function ($scope, vSession, SessionUserDataService, $log, Dialogs, LocationService, $state, vEvents, $rootScope) {
4036    'use strict';
4037    $log = $log.getInstance('TripSearchCardController');
4038    $scope.globalModalShow = $rootScope.globalModalShow;
4039    $scope.globalModalHide = $rootScope.globalModalHide;
4040    $scope.tripplan = null;
4041    $scope.event;
4042    $scope.eventId = $state.params.event;
4043    if (vEvents && $scope.eventId) {
4044        vEvents.get($scope.eventId).then(function (eventObject) {
4045            $scope.event = eventObject;
4046        });
4047    }
4048    $scope.sessionData = SessionUserDataService;
4049    $scope.$watch('tripsearch', function (value) {
4050        $log.debug("$watch('tripsearch')", value);
4051        $scope.updateMatchingTripplan();
4052    });
4053    $scope.$watchCollection('sessionData.tripplans', function (plans) {
4054        $log.debug("$watchCollection('sessionData.tripplans')", plans);
4055        $scope.updateMatchingTripplan();
4056    });
4057    $scope.updateMatchingTripplan = function updateMatchingTripplan() {
4058        $log.debug('BEFORE updateMatchingTripplan: $scope , $rootScope :', $scope.matchingTripplan, $rootScope.matchingTripplan);
4059        if ($scope.tripsearch &&
4060            $scope.sessionData &&
4061            $scope.sessionData.tripplans &&
4062            $scope.sessionData.tripplans.length) {
4063            $rootScope.matchingTripplan = $scope.matchingTripplan =
4064                SessionUserDataService.getTripplanMatchingTripsearch($scope.tripsearch);
4065            $log.debug('UPDATED updateMatchingTripplan: $scope , $rootScope :', $scope.matchingTripplan, $rootScope.matchingTripplan);
4066        }
4067        else {
4068            $rootScope.matchingTripplan = $scope.matchingTripplan = undefined;
4069            $log.debug('UNDEFINED updateMatchingTripplan: $scope , $rootScope :', $scope.matchingTripplan, $rootScope.matchingTripplan);
4070        }
4071    };
4072    $scope.$on('$destroy', function () {
4073        $rootScope.matchingTripplan = $scope.matchingTripplan = undefined;
4074        $log.debug('$destroy matchingTripplan: $scope , $rootScope :', $scope.matchingTripplan, $rootScope.matchingTripplan);
4075    });
4076    $scope.newFavoriteConfirmation =
4077        "<b>Great idea! </b> <br>Adding this to <i class='fa fa-star'></i> <b>" +
4078            CONFIG.savedTripsIdeaModal +
4079            "</b>: <ul><li><b class='em'>saves it to your Dashboard</b> for easy access </li><li><b class='em'>enables extra sharing options</b> to help you connect with even <em>more</em> commuters</li><li><b class=\"em\">does NOT </b> share your full address with anyone</li></ul><footer><b>Press OK</b> to save this trip and view sharing preferences.  <br><b>Press CANCEL</b> to remove this trip from your Favorites.</footer>";
4080    $scope.editTripplan = function (tripplan, options) {
4081        if (tripplan == null) {
4082            $log.debug('editTripplan', 'NEW');
4083            tripplan = {
4084                shared: { public: true, networks: [] },
4085                tripPreferences: { carpool: true, bikepool: false },
4086                from: $scope.tripsearch.from,
4087                to: $scope.tripsearch.to,
4088            };
4089            if (CONFIG.disableCarpoolCreation) {
4090                _.set(tripplan, 'tripPreferences.carpool', false);
4091            }
4092            _.assign(tripplan, options || {});
4093            if ($scope.eventId)
4094                tripplan.relatedEvent = $scope.eventId;
4095            if (vSession.user) {
4096                $scope.tripplan = tripplan;
4097                SessionUserDataService.updateTripplans();
4098            }
4099            else {
4100                return $scope.globalModalShow('account.login');
4101            }
4102        }
4103        else {
4104            $log.debug('editTripplan', 'MATCHING', tripplan);
4105            $scope.tripplan = tripplan.clone();
4106        }
4107    };
4108    $scope.search = function (search, reverse) {
4109        $log.debug('search(search,reverse)', search, reverse);
4110        var fromString, toString;
4111        if (!reverse) {
4112            fromString = LocationService.locationToString(search.from);
4113            toString = LocationService.locationToString(search.to);
4114        }
4115        else {
4116            fromString = LocationService.locationToString(search.to);
4117            toString = LocationService.locationToString(search.from);
4118        }
4119        $state.go('dashboard.plan', {
4120            from: fromString,
4121            to: toString,
4122            eventId: $scope.eventId,
4123        }, {});
4124    };
4125});
4126appControllers.controller('TripplanEditController', function ($scope, SessionUserDataService, $rootScope, vSession, $log, $interval, Dialogs, $state, $stateParams, vEvents, Restangular) {
4127    'use strict';
4128    $log = $log.getInstance('TripplanEditController');
4129    $scope.CONFIG = $rootScope.CONFIG;
4130    $scope._ = $rootScope._ = window._;
4131    $scope.sessionData = SessionUserDataService;
4132    var thisUser = $scope.tripplanUser || $scope.sessionData.user;
4133    var formatLocation = function (property) {
4134        var label = thisUser[property].properties.label;
4135        var coords = thisUser[property].geometry.coordinates;
4136        return { label: label, lat: coords[1], lng: coords[0] };
4137    };
4138    _.defaults($scope.tripplan, { to: {}, from: {} });
4139    var userPlanCheck = !SessionUserDataService.tripplans.length &&
4140        thisUser.homeLocation &&
4141        thisUser.workLocation;
4142    var locationsEmpty = function () {
4143        if ($scope.tripplan.from &&
4144            $scope.tripplan.from.label &&
4145            $scope.tripplan.from.label.length) {
4146            return false;
4147        }
4148        if ($scope.tripplan.to &&
4149            $scope.tripplan.to.label &&
4150            $scope.tripplan.to.label.length) {
4151            return false;
4152        }
4153        return true;
4154    };
4155    if (userPlanCheck && locationsEmpty()) {
4156        var to = formatLocation('workLocation');
4157        var from = formatLocation('homeLocation');
4158        _.assign($scope.tripplan, { to: to, from: from });
4159    }
4160    var event = $stateParams.event || $scope.tripplan.relatedEvent;
4161    if (event && _.isString(event)) {
4162        vEvents.get(event).then(function (eventObject) { return ($scope.event = eventObject); });
4163    }
4164    else if (event && event._id) {
4165        $scope.event = event;
4166    }
4167    $scope.tripplanModes = CONFIG.tripplanModes || [
4168        'carpool',
4169        'walk',
4170        'bike',
4171        'transit',
4172        'drive',
4173    ];
4174    if ($rootScope.PRIMARY_NETWORK) {
4175        $scope.primaryNetworkDefault = _.get($rootScope.PRIMARY_NETWORK, 'capabilities.defaultSharingNetworkEnabled');
4176    }
4177    if (!$scope.tripplan.id && $scope.primaryNetworkDefault) {
4178        $scope.sharedWith = 'networks';
4179        $scope.tripplan.shared.networks = [$rootScope.PRIMARY_NETWORK._id];
4180    }
4181    $scope.loadingNetworks = true;
4182    Restangular.one('users', thisUser._id)
4183        .getList('networks')
4184        .then(function (networks) {
4185        $scope.availableNetworks = networks;
4186        $scope.loadingNetworks = false;
4187    });
4188    $scope.$watch('sharedWith', function (sharedWith) {
4189        if (!sharedWith)
4190            return;
4191        if ($scope.tripplan && $scope.tripplan.shared) {
4192            switch (sharedWith) {
4193                case 'noone':
4194                    $scope.tripplan.shared.public = false;
4195                    $scope.tripplan.shared.networks.length = 0;
4196                    break;
4197                case 'everyone':
4198                    $scope.tripplan.shared.public = true;
4199                    $scope.tripplan.shared.networks.length = 0;
4200                    break;
4201                case 'networks':
4202                    $scope.tripplan.shared.public = false;
4203                    break;
4204            }
4205        }
4206    });
4207    $scope.amigosDefault = {
4208        tripPreferences: {
4209            mode: 'carpool',
4210            accessible: false,
4211            gender: 'any',
4212            role: 'any',
4213        },
4214        schedule: {
4215            days: ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday'],
4216            times: ['09:00 AM', '05:00 PM'],
4217            flexible: false,
4218        },
4219        oneTimeTrip: false,
4220    };
4221    $scope.userDefault = {
4222        tripPreferences: {
4223            mode: _.clone(thisUser.usualMode),
4224            accessible: _.clone(thisUser.publicProfile.accessible),
4225            gender: _.clone(thisUser.publicProfile.genderPreference),
4226            role: _.clone(thisUser.publicProfile.tripRole),
4227        },
4228        schedule: _.cloneDeep(thisUser.usualSchedule),
4229    };
4230    $scope.existingPrefs = {
4231        tripPreferences: _.cloneDeep($scope.tripplan.tripPreferences),
4232        schedule: _.cloneDeep($scope.tripplan.schedule),
4233    };
4234    function boolDefault(category, key, finalDefault) {
4235        var cat = category;
4236        var k = key;
4237        var a = $scope.existingPrefs[cat] || $scope.tripplan[cat];
4238        var b = $scope.userDefault[cat];
4239        var ra = $scope.amigosDefault[cat];
4240        return ((!_.isUndefined(a[k]) ? a[k] : !_.isUndefined(b[k]) ? b[k] : ra[k]) ||
4241            finalDefault);
4242    }
4243    function daysDefault(defaultArray) {
4244        var usrDefaultArray = (($scope.userDefault || {}).schedule || {}).days;
4245        var raDefaultArray = (($scope.amigosDefault || {}).schedule || {}).days;
4246        var fnDefaultArray = defaultArray || [];
4247        var returnArray = (($scope.tripplan || {}).schedule || {}).days;
4248        if (!_.isArray(returnArray) || _.isEmpty(returnArray))
4249            returnArray = usrDefaultArray;
4250        if (!_.isArray(returnArray) || _.isEmpty(returnArray))
4251            returnArray = raDefaultArray;
4252        if (!_.isArray(returnArray) || _.isEmpty(returnArray))
4253            returnArray = fnDefaultArray;
4254        return returnArray;
4255    }
4256    function timesDefault(defaultArray) {
4257        var usrDefaultArray = (($scope.userDefault || {}).schedule || {}).times;
4258        var raDefaultArray = (($scope.amigosDefault || {}).schedule || {}).times;
4259        var fnDefaultArray = defaultArray || [];
4260        var returnArray = (($scope.tripplan || {}).schedule || {}).times;
4261        if (!_.isArray(returnArray) || _.isEmpty(returnArray))
4262            returnArray = usrDefaultArray;
4263        if (!_.isArray(returnArray) || _.isEmpty(returnArray))
4264            returnArray = raDefaultArray;
4265        if (!_.isArray(returnArray) || _.isEmpty(returnArray))
4266            returnArray = fnDefaultArray;
4267        if (_.isArray(returnArray) && returnArray.length !== 2)
4268            returnArray.length = 2;
4269        if (!_.isString(returnArray[0]))
4270            returnArray[0] = raDefaultArray[0] || fnDefaultArray[0];
4271        if (!_.isString(returnArray[1]))
4272            returnArray[1] = raDefaultArray[1] || fnDefaultArray[1];
4273        return returnArray;
4274    }
4275    function modeFromPoolFlags(prefs) {
4276        if (prefs.carpool) {
4277            return 'carpool';
4278        }
4279        if (prefs.bikepool) {
4280            return 'bikepool';
4281        }
4282        if (prefs.walkpool) {
4283            return 'walkpool';
4284        }
4285        if (prefs.transitpool) {
4286            return 'transitpool';
4287        }
4288        return 'drive';
4289    }
4290    function assignPreferencesAndSchedule(userDefault, amigosDefault) {
4291        var existingPrefs = $scope.existingPrefs || $scope.tripplan || {};
4292        var userDefault = userDefault || $scope.userDefault || {};
4293        var amigosDefault = amigosDefault || $scope.amigosDefault || {};
4294        var favePrefs = _.defaults({}, existingPrefs.tripPreferences, userDefault.tripPreferences, amigosDefault.tripPreferences);
4295        var faveSched = _.defaults({}, existingPrefs.schedule, userDefault.schedule, amigosDefault.schedule);
4296        favePrefs.carpool = favePrefs.carpool === true;
4297        favePrefs.bikepool = favePrefs.bikepool === true;
4298        favePrefs.walkpool = favePrefs.walkpool === true;
4299        favePrefs.transitpool = favePrefs.transitpool === true;
4300        if (CONFIG.disableCarpoolCreation) {
4301            favePrefs.carpool = false;
4302        }
4303        favePrefs.mode = modeFromPoolFlags(favePrefs);
4304        faveSched.days = daysDefault();
4305        faveSched.times = timesDefault();
4306        var finalAssign = {
4307            tripPreferences: favePrefs,
4308            schedule: faveSched,
4309        };
4310        return _.assign($scope.tripplan, finalAssign);
4311    }
4312    assignPreferencesAndSchedule();
4313    function updateModeFromPools() {
4314        if (!$scope.tripplan || !$scope.tripplan.tripPreferences)
4315            return;
4316        $scope.tripplan.tripPreferences.mode = modeFromPoolFlags($scope.tripplan.tripPreferences);
4317    }
4318    $scope.$watch('tripplan.tripPreferences.carpool', updateModeFromPools);
4319    $scope.$watch('tripplan.tripPreferences.bikepool', updateModeFromPools);
4320    $scope.$watch('tripplan.tripPreferences.walkpool', updateModeFromPools);
4321    $scope.$watch('tripplan.tripPreferences.transitpool', updateModeFromPools);
4322    var c = 0;
4323    function updatePublicDisplayPreview(user) {
4324        $log.debug('updatePublicDisplayPreview', c++);
4325        $scope.publicDisplayName =
4326            user.publicProfile.displayName || user.firstName;
4327        $scope.publicDisplayBio = user.publicProfile.bio || false;
4328    }
4329    var checkingForUpdate;
4330    updatePublicDisplayPreview(thisUser);
4331    $scope.checkForUserUpdate = function () {
4332        $log.debug('checkForUserUpdate');
4333        var i = 0;
4334        if (angular.isUndefined(checkingForUpdate)) {
4335            checkingForUpdate = $interval(function () {
4336                $log.debug('checkingForUpdate', i++);
4337                Restangular.one('users', thisUser._id)
4338                    .get()
4339                    .then(function (user) {
4340                    updatePublicDisplayPreview(user);
4341                });
4342            }, 2000, 150);
4343        }
4344        window.open($state.href('account.edit.public'), '_blank');
4345    };
4346    $scope.destroyUpdateCheck = function () {
4347        $log.debug('destroyUpdateCheck');
4348        if (angular.isDefined(checkingForUpdate)) {
4349            $interval.cancel(checkingForUpdate);
4350            checkingForUpdate = undefined;
4351        }
4352    };
4353    $scope.$on('$destroy', function () {
4354        $scope.destroyUpdateCheck();
4355    });
4356    $scope.save = function () {
4357        $log.debug('save()', $scope.tripplan);
4358        var success = function (tripplan) {
4359            $log.debug('save()', 'SUCCESS', tripplan);
4360            if (thisUser._id === $scope.sessionData.user._id) {
4361                SessionUserDataService.updateTripplans().then(function () {
4362                    $scope.close();
4363                    if ($state.includes('rideboard')) {
4364                        Dialogs.alert('Your ' +
4365                            $scope.CONFIG.savedTripsNomenclature +
4366                            ' has been saved!');
4367                    }
4368                });
4369            }
4370            else {
4371                $scope.close();
4372            }
4373        };
4374        var error = function (error) {
4375            $log.error('save()', 'ERROR', error);
4376            Dialogs.alert('Oops, we encountered a problem saving your Trip Plan');
4377        };
4378        if (!$scope.tripplan._id)
4379            thisUser.post('tripplans', $scope.tripplan).then(success, error);
4380        else
4381            $scope.tripplan.put().then(success, error);
4382    };
4383    $scope.remove = function () {
4384        $log.debug('remove()');
4385        var success = function () {
4386            $log.debug('remove()', 'SUCCESS');
4387            if (thisUser._id === $scope.sessionData.user._id) {
4388                SessionUserDataService.updateTripplans().then(function () {
4389                    $scope.close();
4390                });
4391            }
4392        };
4393        var error = function (error) {
4394            $log.error('remove()', 'ERROR', error);
4395            Dialogs.alert('Oops, we encountered a problem removing your Trip Plan');
4396        };
4397        var confirm = function (confirmed) {
4398            $log.debug('remove()', 'confirmed?', confirmed);
4399            if (confirmed)
4400                $scope.tripplan.remove().then(success, error);
4401        };
4402        if ($scope.tripplan.from.lat && $scope.tripplan.to.lat) {
4403            Dialogs.confirm({
4404                message: 'Are you sure you want to remove your trip? If this trip is shared, it will be removed from carpool results.',
4405                callback: confirm,
4406            });
4407        }
4408        else {
4409            confirm(true);
4410        }
4411    };
4412    $scope.close = function () {
4413        $log.debug('close()');
4414        $scope.$parent.tripplan = $scope.tripplan = undefined;
4415        $scope.$emit('tripplanEditClose');
4416        $scope.hideModal();
4417    };
4418});
4419appControllers.controller('TripplanViewController', function ($scope, $rootScope, $state, vSession, $log, Dialogs, SessionUserDataService, LocationService, vEvents) {
4420    'use strict';
4421    $log = $log.getInstance('TripplanViewController');
4422    $scope.CONFIG = $rootScope.CONFIG;
4423    $scope.editTripplan = undefined;
4424    $scope.event = null;
4425    $scope.eventId = null;
4426    $scope.edit = function TripplanViewController_scope_edit(plan) {
4427        $log.debug('edit(plan)', plan);
4428        $scope.editTripplan = plan.clone();
4429        if ($scope.editTripplan.relatedEvent &&
4430            _.isObject($scope.editTripplan.relatedEvent) &&
4431            $scope.editTripplan.relatedEvent.hasOwnProperty('_id')) {
4432            $scope.event = $scope.editTripplan.relatedEvent;
4433            $scope.editTripplan.relatedEvent = $scope.editTripplan.relatedEvent._id;
4434        }
4435    };
4436    $scope.search = function TripplanViewController_scope_search(plan, reverse) {
4437        $log.debug('search(plan,reverse)', plan, reverse);
4438        var fromString, toString, searchDate, searchTime;
4439        if (!reverse) {
4440            fromString = LocationService.locationToString(plan.from);
4441            toString = LocationService.locationToString(plan.to);
4442        }
4443        else {
4444            fromString = LocationService.locationToString(plan.to);
4445            toString = LocationService.locationToString(plan.from);
4446        }
4447        var search = {
4448            from: fromString,
4449            to: toString,
4450            date: searchDate,
4451            time: searchTime,
4452        };
4453        if (plan.relatedEvent) {
4454            search.event = plan.relatedEvent._id;
4455            var firstOccurrence = plan.relatedEvent.occurrences[0];
4456            if (!reverse) {
4457                search.date = moment(firstOccurrence.startDateTime)
4458                    .startOf('day')
4459                    .format('YYYY-MM-DD');
4460                search.time = moment(firstOccurrence.startDateTime)
4461                    .subtract(2, 'hours')
4462                    .format('hh:mm A');
4463            }
4464            else {
4465                search.date = moment(firstOccurrence.endDateTime)
4466                    .startOf('day')
4467                    .format('YYYY-MM-DD');
4468                search.time = moment(firstOccurrence.endDateTime)
4469                    .add(30, 'minutes')
4470                    .format('hh:mm A');
4471            }
4472        }
4473        $state.go('dashboard.plan', search);
4474    };
4475});
4476appControllers.controller('NetworkAssocProfileController', function ($scope, $state, $timeout, $stateParams, vUser, vNetworks, $log, Dialogs, RegistrationService, CONFIG) {
4477    'use strict';
4478    $log = $log.getInstance('NetworkAssocProfileController');
4479    var networkId = $stateParams.networkId;
4480    var joinId = $stateParams.join;
4481    var userNetworks, userManagedNetworks;
4482    var requestObj = joinId
4483        ? {
4484            joinId: joinId,
4485        }
4486        : null;
4487    var countDracula = 0;
4488    $scope.$watch('session.user', function (user) {
4489        userNetCheck();
4490    });
4491    var userNetCheck = function () {
4492        $scope.isMember = session.user
4493            ? _.includes(session.user.networks, networkId)
4494            : false;
4495        $scope.isManager = session.user
4496            ? _.includes(session.user.managedNetworks, networkId)
4497            : false;
4498        if ($scope.isMember) {
4499            session.user.getList('networks').then(function (nets) {
4500                userNetworks = nets;
4501                $scope.network = _.find(nets, {
4502                    _id: networkId,
4503                });
4504                $scope.isPublic = !!$scope.network.isPublic;
4505                $scope.validJoinId = joinId === $scope.network.joinId;
4506            });
4507        }
4508        else {
4509            $log.debug('userNetCheck() - attempting to get networks');
4510            vNetworks.get(networkId, requestObj).then(getNetSuccess, getNetFault);
4511        }
4512        if ($scope.isManager) {
4513            session.user.getList('managednetworks').then(function (nets) {
4514                userManagedNetworks = nets;
4515            });
4516        }
4517    };
4518    $scope.loginOrRegister = function (modal) {
4519        if ($scope.network && !$scope.isPublic)
4520            RegistrationService.addPrivateNetwork($scope.network);
4521        if ($scope.network &&
4522            $scope.network.capabilities &&
4523            $scope.network.capabilities.primaryNetwork) {
4524            RegistrationService.selectedPrimaryNetwork = $scope.network._id;
4525        }
4526        $scope.globalModalShow(modal);
4527    };
4528    var getNetSuccess = function (network) {
4529        $log.debug('vNetworks.get()', 'Success', network);
4530        $scope.network = network;
4531        $scope.isPublic = !!network.isPublic;
4532        $scope.validJoinId = joinId === network.joinId;
4533    };
4534    var getNetFault = function (error) {
4535        if (!countDracula) {
4536            $timeout(function () {
4537                countDracula = 1;
4538                return userNetCheck();
4539            }, 500);
4540        }
4541        else {
4542            $log.debug('vNetworks.get()', 'Error', error);
4543            countDracula = 0;
4544            Dialogs.alert("The network you're looking for cannot be found.");
4545            $state.go('home');
4546        }
4547    };
4548    $scope.joinNetwork = function () {
4549        var onSuccess = function () {
4550            $log.debug('addNetwork', 'Success');
4551            Dialogs.alert('You are now a member!');
4552            session.refresh();
4553            $state.go('dashboard.dashboard');
4554        };
4555        var onFault = function (err) {
4556            $log.debug('addNetwork', 'Error', err);
4557            session.refresh();
4558            var _a = _.get(err, 'data', {}), error = _a.error, name = _a.name;
4559            var memberExists = function (val) { return _.includes(val, 'Exists'); };
4560            if (memberExists(error) || memberExists(name))
4561                return Dialogs.alert('You are already a member!');
4562            Dialogs.alert({
4563                unsafeMessage: "There was an error joining the network. <br> <strong>Error</strong>: ".concat(_.startCase(error)),
4564            });
4565        };
4566        if ($scope.isPublic) {
4567            session.user
4568                .post('networks', {
4569                network: networkId,
4570            })
4571                .then(onSuccess, onFault);
4572        }
4573        else if (!$scope.isPublic) {
4574            session.user
4575                .post('networks', {
4576                network: networkId,
4577                joinId: joinId,
4578            })
4579                .then(onSuccess, onFault);
4580        }
4581    };
4582    $scope.leaveNetwork = function () {
4583        var onConfirmResult = function (confirmed) {
4584            var onSuccess = function () {
4585                $log.debug('removeNetwork', 'Success');
4586                Dialogs.alert('Membership was removed!');
4587                session.refresh();
4588            };
4589            var onFault = function (error) {
4590                $log.debug('removeNetwork', 'Error', error);
4591                session.refresh();
4592                Dialogs.alert('Your membership was not removed.');
4593            };
4594            if (confirmed)
4595                session.user
4596                    .one('networks', networkId)
4597                    .remove()
4598                    .then(onSuccess, onFault);
4599        };
4600        Dialogs.confirm({
4601            message: 'Are you sure you want to leave this network?',
4602            callback: onConfirmResult,
4603        });
4604    };
4605    $timeout(function () {
4606        document.title = CONFIG.siteTitle + ' - Join ' + $scope.network.name;
4607    }, 1500);
4608});
4609appControllers.controller('SupportEmailController', function ($scope, $rootScope, $http, $log, Dialogs, gRecaptcha, $state) {
4610    'use strict';
4611    $log = $log.getInstance('SupportEmailController');
4612    $log.debug('loaded.');
4613    if (!session.user && CONFIG.supportDisableNonUserSending) {
4614        $state.go('home');
4615    }
4616    $scope.supportEmail = {};
4617    if (CONFIG.supportHideRequestType) {
4618        var defaultType = CONFIG.supportOptions.find(function (opt) {
4619            return opt.option === 'General Request';
4620        });
4621        if (!defaultType && CONFIG.supportHideRequestType) {
4622            defaultType = { option: 'General Request', supportEmail: null };
4623        }
4624        $scope.supportEmail.type = defaultType;
4625    }
4626    $scope.supportEmail.fromUrl = $rootScope.fromUrl;
4627    if (session.user)
4628        $scope.supportEmail.name =
4629            session.user.firstName + ' ' + session.user.lastName;
4630    if (session.user && session.user.email)
4631        $scope.supportEmail.email = session.user.email;
4632    $scope.primaryNetworkSupportEmail = _.get($rootScope.PRIMARY_NETWORK, 'supportEmailAddress');
4633    if (!$scope.primaryNetworkSupportEmail) {
4634        $scope.$watch('supportEmail.type', function (type) {
4635            if (type) {
4636                $scope.supportEmail.sendTo = type.supportEmail;
4637            }
4638        });
4639    }
4640    if ($rootScope.PRIMARY_NETWORK && $scope.primaryNetworkSupportEmail) {
4641        $scope.supportEmail.sendTo = $scope.primaryNetworkSupportEmail;
4642        $scope.supportEmail.network = $rootScope.PRIMARY_NETWORK._id;
4643    }
4644    gRecaptcha.initialize({ key: CONFIG.recaptchaPublicKey });
4645    $scope.sendEmail = function () {
4646        if (!session.user && CONFIG.supportDisableNonUserSending) {
4647            Dialogs.alert('You must be logged in to send an email.');
4648            return;
4649        }
4650        gRecaptcha
4651            .execute({ action: 'supportEmail' })
4652            .then(function (token) {
4653            $scope.supportEmail.recaptchaToken = token;
4654            $log.debug('sendEmail', $scope.supportEmail);
4655            return $http.post('/api/v1/support/email', $scope.supportEmail);
4656        })
4657            .then(function (result) {
4658            Dialogs.alert('Your request has been sent!');
4659            $log.debug('Message was sent', result);
4660            ga('send', 'event', 'form submission', 'submit', 'contact form');
4661            $scope.globalModalHide();
4662        }, function (err) {
4663            Dialogs.alert('Whoops, something went wrong! Check your message and try again.');
4664            $log.error('Message was not sent', err);
4665        });
4666    };
4667});
4668appControllers.controller('CarpoolFlagEmailController', function ($scope, $rootScope, $http, $log, Dialogs, gRecaptcha) {
4669    $log = $log.getInstance('CarpoolFlagEmailController');
4670    $log.debug('loaded.');
4671    $scope.carpoolFlagEmail = {
4672        carpool: $scope.carpool._id,
4673    };
4674    if (session.user)
4675        $scope.carpoolFlagEmail.name =
4676            session.user.firstName + ' ' + session.user.lastName;
4677    if (session.user && session.user.email)
4678        $scope.carpoolFlagEmail.email = session.user.email;
4679    gRecaptcha.initialize({ key: CONFIG.recaptchaPublicKey });
4680    $scope.sendEmail = function () {
4681        gRecaptcha
4682            .execute({ action: 'carpoolFlagEmail' })
4683            .then(function (token) {
4684            $scope.carpoolFlagEmail.recaptchaToken = token;
4685            $log.debug('sendEmail', $scope.carpoolFlagEmail);
4686            return $http.post('/api/v1/support/flag-carpool', $scope.carpoolFlagEmail);
4687        })
4688            .then(function (result) {
4689            Dialogs.alert('Your report has been sent!');
4690            $log.debug('Message was sent', result);
4691            ga('send', 'event', 'form submission', 'submit', 'contact form');
4692            $scope.globalModalHide();
4693        }, function (err) {
4694            Dialogs.alert('Whoops, something went wrong! Check your message and try again.');
4695            $log.error('Message was not sent', err);
4696        });
4697    };
4698});
4699appControllers.controller('CarpoolOptInController', function ($scope, $vhttp, $log, vSession, vUser, vNetworks, vTripplans, $rootScope, $q, $state) {
4700    'use strict';
4701    $log = $log.getInstance('CarpoolOptInController');
4702    $scope._ = _;
4703    var userId = $scope.userId || vSession.user._id;
4704    $scope.trips;
4705    init();
4706    function init() {
4707        vUser.one(userId).getList('networks').then(setTrips, _.noop);
4708    }
4709    function setTrips(userNetworks) {
4710        var eligibleTrips = $scope.trips;
4711        $scope.netLookup = _.keyBy(userNetworks, '_id');
4712        _.forEach(eligibleTrips, function (trip) {
4713            if (isPrimaryOnlySharedTrip(trip))
4714                trip.shared.public = true;
4715        });
4716        $scope.userTripPlans = eligibleTrips;
4717        $scope.checkAllShared();
4718    }
4719    function onShareToggle(trip) {
4720        $scope.checkAllShared();
4721    }
4722    $scope.onShareToggle = onShareToggle;
4723    $scope.shareAllTrips = function (isShared) {
4724        _.forEach($scope.userTripPlans, function (trip) {
4725            trip.shared.public = isShared;
4726        });
4727        $scope.allTripsShared = isShared;
4728    };
4729    $scope.checkAllShared = function () {
4730        $scope.allTripsShared = !_.some($scope.userTripPlans, function (trip) { return !trip.shared.public; });
4731    };
4732    function isPrimaryOnlySharedTrip(trip) {
4733        if (trip.shared.networks.length > 1)
4734            return false;
4735        var publicNetworkId = trip.shared.networks[0];
4736        return _.get($scope.netLookup[publicNetworkId], 'capabilities.primaryNetwork', false);
4737    }
4738    $scope.updateTripplans = function () {
4739        _.set(vSession.user, 'customProfileFields.carpoolOptIn', true);
4740        _.forEach($scope.userTripPlans, function (trip) {
4741            if (trip.shared.public)
4742                trip.shared.networks = [];
4743        });
4744        $q.all.apply($q, __spreadArray(__spreadArray([], _.map($scope.userTripPlans, function (trip) { return trip.put(); }), false), [vSession.user.put()], false)).then(function (res) {
4745            $rootScope.globalModalHide();
4746            $state.reload();
4747        }, _.noop);
4748    };
4749});
4750appControllers.controller('AccountMergeModalController', function ($scope, $rootScope, vUser, vSession) {
4751    $scope.userNetworks;
4752    $scope.confirmMergeNotice = function () {
4753        _.set(vSession.user, 'customProfileFields.primaryMergeNotice', true);
4754        vSession.user.put().then(function () {
4755            $rootScope.globalModalHide();
4756        }, _.noop);
4757    };
4758});
4759appControllers.controller('BadgeDisplayController', function ($scope, $rootScope, $state, $stateParams, $location, $log, vUser, SessionUserDataService, Dialogs) {
4760    'use strict';
4761    $log = $log.getInstance('BadgeDisplayController');
4762    $scope.sessionData = SessionUserDataService;
4763    $scope.badgeView = 4;
4764    var user, badges;
4765    var badgePidgeon = $rootScope.badgePidgeon || {};
4766    $scope.badgeIndex = 0;
4767    $scope.currentBadge = null;
4768    var badgeImgDir = '/img/badges/';
4769    $scope.$watch('currentBadge', function (newVal) {
4770        if (newVal && newVal.images)
4771            newVal.imgUrls = _.mapValues(newVal.images, function (img) {
4772                return badgeImgDir + img;
4773            });
4774    });
4775    $scope.hasPrevBadge = function () {
4776        return $scope.badgeIndex > 0 && $scope.badges.length;
4777    };
4778    $scope.hasNextBadge = function () {
4779        return $scope.badgeIndex < $scope.badges.length - 1;
4780    };
4781    $scope.nextBadge = function () {
4782        $scope.badgeIndex++;
4783        $scope.currentBadge = $scope.badges[$scope.badgeIndex];
4784        $scope.social = {
4785            url: $location.protocol() +
4786                '://' +
4787                $location.host() +
4788                '/#/badge/' +
4789                $scope.currentBadge._id +
4790                '/' +
4791                user._id,
4792            title: $rootScope.CONFIG.badgeShareTextPt1 +
4793                $scope.currentBadge.description +
4794                $rootScope.CONFIG.badgeShareTextPt2,
4795            description: 'I just earned a ' +
4796                $scope.currentBadge.name +
4797                ' badge on ' +
4798                $rootScope.CONFIG.siteTitle +
4799                '</var> for logging <var description>' +
4800                $scope.currentBadge.description +
4801                '</var>.',
4802            image: $location.protocol() +
4803                '://' +
4804                $location.host() +
4805                '/img/badges/' +
4806                $scope.currentBadge.images.large,
4807        };
4808    };
4809    $scope.prevBadge = function () {
4810        $scope.badgeIndex--;
4811        $scope.currentBadge = $scope.badges[$scope.badgeIndex];
4812        $scope.social = {
4813            url: $location.protocol() +
4814                '://' +
4815                $location.host() +
4816                '/#/badge/' +
4817                $scope.currentBadge._id +
4818                '/' +
4819                user._id,
4820            title: $rootScope.CONFIG.badgeShareTextPt1 +
4821                $scope.currentBadge.description +
4822                $rootScope.CONFIG.badgeShareTextPt2,
4823            description: 'I just earned a ' +
4824                $scope.currentBadge.name +
4825                ' badge on ' +
4826                $rootScope.CONFIG.siteTitle +
4827                ' for logging ' +
4828                $scope.currentBadge.description +
4829                '.',
4830            image: $location.protocol() +
4831                '://' +
4832                $location.host() +
4833                '/img/badges/' +
4834                $scope.currentBadge.images.large,
4835        };
4836    };
4837    if (badgePidgeon.userId) {
4838        $log.debug('badgeView=2');
4839        $scope.badgeView = 2;
4840        vUser
4841            .one(badgePidgeon.userId)
4842            .one('profile')
4843            .get()
4844            .then(function (result) {
4845            $scope.user = user = result;
4846            $log.debug(result);
4847            vUser
4848                .one(badgePidgeon.userId)
4849                .one('badges')
4850                .get()
4851                .then(function (result) {
4852                $log.debug(result);
4853                $scope.badges = badges = result;
4854                if ($scope.badgeId)
4855                    $scope.badgeIndex = _.findIndex(badges, {
4856                        _id: $scope.badgeId,
4857                    });
4858                $scope.currentBadge = $scope.badges[$scope.badgeIndex];
4859            }, function (fault) {
4860                $log.error('Badge Not Found');
4861                badges = null;
4862                return faultMsg();
4863            });
4864        }, function (fault) {
4865            $log.error('User Not Found');
4866            user = null;
4867            return faultMsg();
4868        });
4869    }
4870    else if (!!session.user &&
4871        !!$scope.sessionData &&
4872        !!$scope.sessionData.badges &&
4873        !!$scope.sessionData.badges.length) {
4874        $log.debug('badgeView=3');
4875        $scope.badgeView = 3;
4876        user = session.user;
4877        badges = $scope.sessionData.badges;
4878        if ($scope.badgeId)
4879            $scope.badgeIndex = _.findIndex(badges, { _id: $scope.badgeId });
4880        $scope.currentBadge = badges[$scope.badgeIndex];
4881        $log.debug($scope, $scope.badgeId);
4882        $scope.social = {
4883            url: $location.protocol() +
4884                '://' +
4885                $location.host() +
4886                '/#/badge/' +
4887                $scope.currentBadge._id +
4888                '/' +
4889                user._id,
4890            title: $rootScope.CONFIG.badgeShareTextPt1 +
4891                $scope.currentBadge.description +
4892                $rootScope.CONFIG.badgeShareTextPt2,
4893            description: 'I just earned a ' +
4894                $scope.currentBadge.name +
4895                ' badge on ' +
4896                $rootScope.CONFIG.siteTitle +
4897                ' for logging ' +
4898                $scope.currentBadge.description +
4899                '.',
4900            image: $location.protocol() +
4901                '://' +
4902                $location.host() +
4903                '/img/badges/' +
4904                $scope.currentBadge.images.large,
4905        };
4906    }
4907    $scope.badges = badges || null;
4908    $scope.user = user || null;
4909    function faultMsg() {
4910        Dialogs.alert("Sorry, we can't seem to find that user or award.");
4911        $state.go('home');
4912        $rootScope.globalModalHide();
4913        $rootScope.badgePidgeon = null;
4914    }
4915    if ($scope.badgeView == 4)
4916        return faultMsg();
4917    return ($rootScope.badgePidgeon = null);
4918});
4919appControllers.controller('FAQModalController', function ($scope, $rootScope, $state, $location, $log) {
4920    'use strict';
4921    $log = $log.getInstance('FAQModalController');
4922    var tabsArray = [
4923        'account',
4924        'loggingTrips',
4925        'tripPlanning',
4926        'rideSharing',
4927        'systemInfo',
4928        'challenges',
4929        'incentives',
4930        'events',
4931        'surveys',
4932        'rideshares',
4933        'locations',
4934        'proxy',
4935        'schoolpool',
4936        'commuteperks',
4937    ];
4938    var defaultTab = tabsArray[0];
4939    var state = $state && $state.current && $state.current.name
4940        ? $state.current.name
4941        : undefined;
4942    angular.forEach(tabsArray, function (tab) {
4943        if (tab && state && state.indexOf(tab) > -1)
4944            return (defaultTab = tab);
4945    });
4946    return ($scope.visibleTab = defaultTab);
4947});
4948;
4949'use strict';
4950var appDirectives = angular.module('vtmoFront');
4951appDirectives.directive('timeSelect', function () {
4952    return {
4953        restrict: 'EA',
4954        scope: {
4955            ngModel: '=',
4956            form: '?=',
4957        },
4958        link: function (scope, element) {
4959            var customTimes = [];
4960            scope.removeCustomTime = function () {
4961                if (customTimes.length && customTimes.indexOf($scope.plan.time) < 0) {
4962                    $scope.times = _.difference($scope.times, customTimes);
4963                    customTimes = [];
4964                }
4965            };
4966            scope.addMinute = function (val) {
4967                var date = moment($scope.plan.time, timeformat)
4968                    .add(val, 'm')
4969                    .format(timeformat);
4970                $scope.times = customTimes.length
4971                    ? _.difference($scope.times, customTimes).concat([date])
4972                    : $scope.times.concat([date]);
4973                $scope.plan.time = _.clone(date);
4974                customTimes.push(date);
4975                scope.form.$setDirty();
4976            };
4977        },
4978    };
4979});
4980appDirectives.directive('compile', [
4981    '$compile',
4982    function ($compile) {
4983        return function (scope, element, attrs) {
4984            var compileWatcher = scope.$watch(function (scope) {
4985                return scope.$eval(attrs.compile);
4986            }, function (value) {
4987                element.html(value);
4988                $compile(element.contents())(scope);
4989                compileWatcher();
4990            });
4991        };
4992    },
4993]);
4994appDirectives.directive('editableSelect', function () {
4995    return {
4996        restrict: 'E',
4997        require: '^ngModel',
4998        scope: {
4999            ngModel: '=',
5000        },
5001        replace: true,
5002        templateUrl: 'templates/system/directive/dateSearchInput.html',
5003        link: function (scope, element) {
5004            var timeFormat = 'hh:mm A';
5005            var interval = 15;
5006            scope.options = getTimesArray();
5007            scope.select = function (val) {
5008                if (val)
5009                    scope.ngModel = val;
5010                scope.triggerFormChange();
5011            };
5012            scope.setAddOnBorder = function () {
5013                scope.addFocusClass = true;
5014            };
5015            scope.isDate = function (val) {
5016                return moment(val, timeFormat).isValid();
5017            };
5018            scope.triggerFormChange = function () {
5019                if (!scope.dateSearchForm.$isDirty)
5020                    scope.dateSearchForm.$setDirty();
5021            };
5022            function getTimesArray() {
5023                var times = [];
5024                for (var time = moment('12:00 AM', timeFormat); time < moment('11:59 PM', timeFormat); time.add(interval, 'minutes')) {
5025                    times.push(time.format(timeFormat));
5026                }
5027                if (times.indexOf(scope.ngModel) < 0)
5028                    times.push(moment(scope.ngModel, timeFormat).format(timeFormat));
5029                return times;
5030            }
5031        },
5032    };
5033});
5034appDirectives.directive('adminUserSelect', function (vSession) {
5035    return {
5036        restrict: 'EA',
5037        scope: {
5038            ngModel: '=?',
5039            selectedUser: '=?',
5040            fetchUrl: '@?',
5041        },
5042        link: function (scope, element, attrs, controllers) {
5043            var availableUsers = [];
5044            var url = scope.fetchUrl || '/api/v1/admin/reports/users';
5045            scope.$watch('ngModel', function (newValue) {
5046                if (!newValue) {
5047                    $(element).select2('val', '');
5048                }
5049            });
5050            function initSelect2() {
5051                $(element)
5052                    .on('change', function (e) {
5053                    if (e.val) {
5054                        scope.$apply(function () {
5055                            scope.ngModel = e.val;
5056                            var selectedUser = null;
5057                            _.forEach(availableUsers, function (u) {
5058                                if (u.id === e.val)
5059                                    selectedUser = u;
5060                            });
5061                            scope.selectedUser = selectedUser;
5062                        });
5063                    }
5064                    else {
5065                        scope.selectedUser = null;
5066                        scope.ngModel = null;
5067                    }
5068                })
5069                    .select2({
5070                    minimumInputLength: 0,
5071                    ajax: {
5072                        params: {
5073                            headers: {
5074                                Authorization: 'Bearer ' + vSession.token,
5075                            },
5076                        },
5077                        url: url,
5078                        dataType: 'json',
5079                        quietMillis: 300,
5080                        data: function (text, page) {
5081                            var baseQueryOptions = {
5082                                count: 10,
5083                                or: true,
5084                                sort: JSON.stringify({
5085                                    lastName: 1,
5086                                }),
5087                            };
5088                            var terms = _.split(_.trim(text), /\s+/);
5089                            var fullTerm = _.join(terms, '');
5090                            var query;
5091                            if (fullTerm.includes('@')) {
5092                                query = {
5093                                    email: fullTerm,
5094                                };
5095                            }
5096                            else if (terms.length === 2) {
5097                                delete baseQueryOptions.or;
5098                                query = {
5099                                    firstName: _.first(terms),
5100                                    lastName: _.last(terms),
5101                                };
5102                            }
5103                            else {
5104                                query = {
5105                                    firstName: fullTerm,
5106                                    lastName: fullTerm,
5107                                    email: fullTerm,
5108                                };
5109                            }
5110                            return __assign(__assign({}, baseQueryOptions), { query: JSON.stringify(query) });
5111                        },
5112                        results: function (data, page) {
5113                            availableUsers = [];
5114                            _.forEach(data.results, function (user) {
5115                                availableUsers.push({
5116                                    id: user._id,
5117                                    text: user.firstName +
5118                                        ' ' +
5119                                        user.lastName +
5120                                        ' (' +
5121                                        user.email +
5122                                        ')',
5123                                    firstName: user.firstName,
5124                                    lastName: user.lastName,
5125                                    email: user.email,
5126                                    customProfileFields: user.customProfileFields,
5127                                });
5128                            });
5129                            return {
5130                                results: availableUsers,
5131                            };
5132                        },
5133                    },
5134                    initSelection: function (element, callback) {
5135                        callback(null);
5136                    },
5137                });
5138            }
5139            initSelect2();
5140        },
5141    };
5142});
5143appDirectives.directive('networkAdminUserSelect', function ($http, $timeout, vSession) {
5144    return {
5145        template: '<select class="network-member-select" kendo-multi-select k-options="selectOptions" ng-model="selectedUsers" ></select>',
5146        restrict: 'EA',
5147        scope: {
5148            selectedUsers: '=',
5149            placeholder: '@?',
5150            multiselect: '=?',
5151            networks: '=?',
5152            onChange: '&',
5153        },
5154        link: function ($scope, element, attrs, controllers) {
5155            var dataSource = new kendo.data.DataSource({
5156                transport: {
5157                    read: {
5158   
5158                     url: '/api/v1/network-member-autocomplete',
5159                        beforeSend: function (req) {
5160                            var value;
5161                            var self = this;
5162                            try {
5163                                value = dataSource._filter.filters[0].value;
5164                            }
5165                            catch (e) { }
5166                            var urlWithoutFilters = this.url.split('&filter')[0];
5167                            this.url = urlWithoutFilters;
5168                            if (value) {
5169                                this.url += '&find=' + encodeURI(value);
5170                            }
5171                            _.forEach($scope.networks, function (network) {
5172                                self.url += '&networks=' + network;
5173                            });
5174                            req.setRequestHeader('Authorization', 'Bearer ' + vSession.token);
5175                        },
5176                    },
5177                },
5178                pageSize: 20,
5179                serverPaging: true,
5180                serverFiltering: true,
5181                serverSorting: true,
5182            });
5183            dataSource.read();
5184            $scope.selectOptions = {
5185                placeholder: attrs.placeholder || 'Select Users',
5186                dataTextField: 'find',
5187                dataValueField: '_id',
5188                value: $scope.selectedUsers,
5189                valuePrimitive: true,
5190                autoBind: false,
5191                delay: 1000,
5192                virtual: {
5193                    mapValueTo: 'dataItem',
5194                    valueMapper: function (options) {
5195                        var lookup = _.isArray(options.value)
5196                            ? options.value.join()
5197                            : options.value;
5198                        var kendoEl = $('select.network-member-select');
5199                        var multiselect = kendoEl.data('kendoMultiSelect');
5200                        var dataItem = multiselect.dataItems();
5201                        var self = this;
5202                        var params = { userLookup: lookup };
5203                        if ($scope.networks && $scope.networks.length)
5204                            params.networks = $scope.networks;
5205                        $http
5206                            .get('/api/v1/network-member-autocomplete', {
5207                            params: params,
5208                            headers: {
5209                                Authorization: 'Bearer ' + vSession.token,
5210                                'Content-Type': 'application/json',
5211                            },
5212                        })
5213                            .then(function (users) {
5214                            users = users.data;
5215                            options.success(users);
5216                        });
5217                    },
5218                },
5219                dataSource: dataSource,
5220                itemTemplate: '<span class="k-state-default" style="font-size:90%"><b>#: data.firstName # #: data.lastName #</b> <span class="small">(#: data.email #)</span></span>',
5221                change: function (e) {
5222                    var value = this.value();
5223                    if ($scope.onChange) {
5224                        $scope.onChange(value);
5225                    }
5226                },
5227            };
5228            setTimeout(function () {
5229                var kendoEl = $('select.network-member-select');
5230                var kendoMultiSelect = kendoEl.data('kendoMultiSelect');
5231                $scope.multiselect = kendoMultiSelect;
5232            }, 100);
5233        },
5234    };
5235});
5236appDirectives.directive('tripsearchCard', function ($log, vSession, $rootScope, $location, $timeout) {
5237    $log = $log.getInstance('tripsearch-card');
5238    return {
5239        restrict: 'EA',
5240        templateUrl: '/templates/tripplan/results/TripSearchCard.html',
5241        scope: {
5242            tripsearchCard: '=',
5243        },
5244        controller: 'TripSearchCardController',
5245        link: function (scope, element, attrs, controllers) {
5246            scope.session = vSession;
5247            scope.social = {};
5248            scope.social.title =
5249                'Transportation Options @ ' + $rootScope.CONFIG.siteTitle;
5250            scope.social.description =
5251                'Find carpools and other transportation options at ' +
5252                    $rootScope.CONFIG.siteTitle +
5253                    '.';
5254            $log.debug('tripsearchCard changed', scope.tripsearch);
5255            if (scope.tripsearchCard) {
5256                scope.tripsearch = _.clone(scope.tripsearchCard);
5257            }
5258            else {
5259                scope.tripsearch = undefined;
5260            }
5261            $timeout(function () {
5262                scope.initialized = true;
5263            }, 300);
5264        },
5265    };
5266});
5267appDirectives.directive('tripsearchHistoryCard', function ($log, vSession, CONFIG) {
5268    $log = $log.getInstance('tripsearch-history-card');
5269    return {
5270        restrict: 'EA',
5271        templateUrl: '/templates/tripplan/TripsearchHistoryCard.html',
5272        scope: {
5273            tripsearchHistoryCard: '=',
5274        },
5275        controller: 'TripSearchCardController',
5276        link: function (scope, element, attrs, controllers) {
5277            scope.CONFIG = CONFIG;
5278            scope.session = vSession;
5279            scope.$watch('tripsearchHistoryCard', function (value) {
5280                $log.debug('tripsearchHistoryCard changed', value);
5281                if (value) {
5282                    scope.tripsearch = value.clone();
5283                }
5284                else {
5285                    scope.tripsearch = undefined;
5286                }
5287            });
5288        },
5289    };
5290});
5291appDirectives.directive('bikepoolPrompt', function ($log, $rootScope, vSession, CONFIG) {
5292    $log = $log.getInstance('bikepool-prompt');
5293    return {
5294        restrict: 'EA',
5295        templateUrl: '/templates/tripplan/results/BikepoolPrompt.html',
5296        scope: {
5297            bikepoolPrompt: '=',
5298        },
5299        controller: 'TripSearchCardController',
5300        link: function (scope, element, attrs, controllers) {
5301            scope.CONFIG = CONFIG;
5302            scope.session = vSession;
5303            scope.globalModalShow = $rootScope.globalModalShow;
5304            scope.$watch('bikepoolPrompt', function (value) {
5305                $log.debug('bikepoolPrompt changed', value);
5306                if (value) {
5307                    scope.tripsearch = value.clone();
5308                }
5309                else {
5310                    scope.tripsearch = undefined;
5311                }
5312            });
5313        },
5314    };
5315});
5316appDirectives.directive('walkpoolPrompt', function ($log, $rootScope, vSession, CONFIG) {
5317    $log = $log.getInstance('walkpool-prompt');
5318    return {
5319        restrict: 'EA',
5320        templateUrl: '/templates/tripplan/results/WalkpoolPrompt.html',
5321        scope: {
5322            walkpoolPrompt: '=',
5323        },
5324        controller: 'TripSearchCardController',
5325        link: function (scope, element, attrs, controllers) {
5326            scope.CONFIG = CONFIG;
5327            scope.session = vSession;
5328            scope.globalModalShow = $rootScope.globalModalShow;
5329            scope.$watch('walkpoolPrompt', function (value) {
5330                $log.debug('walkpoolPrompt changed', value);
5331                if (value) {
5332                    scope.tripsearch = value.clone();
5333                }
5334                else {
5335                    scope.tripsearch = undefined;
5336                }
5337            });
5338        },
5339    };
5340});
5341appDirectives.directive('transitpoolPrompt', function ($log, $rootScope, vSession, CONFIG) {
5342    $log = $log.getInstance('transitpool-prompt');
5343    return {
5344        restrict: 'EA',
5345        templateUrl: '/templates/tripplan/results/TransitpoolPrompt.html',
5346        scope: {
5347            transitpoolPrompt: '=',
5348        },
5349        controller: 'TripSearchCardController',
5350        link: function (scope, element, attrs, controllers) {
5351            scope.CONFIG = CONFIG;
5352            scope.session = vSession;
5353            scope.globalModalShow = $rootScope.globalModalShow;
5354            scope.$watch('transitpoolPrompt', function (value) {
5355                $log.debug('transitpoolPrompt changed', value);
5356                if (value) {
5357                    scope.tripsearch = value.clone();
5358                }
5359                else {
5360                    scope.tripsearch = undefined;
5361                }
5362            });
5363        },
5364    };
5365});
5366appDirectives.directive('carpoolPrompt', function ($log, $rootScope, vSession, CONFIG) {
5367    $log = $log.getInstance('carpool-prompt');
5368    return {
5369        restrict: 'EA',
5370        templateUrl: '/templates/tripplan/results/CarpoolPrompt.html',
5371        scope: {
5372            carpoolPrompt: '=',
5373        },
5374        controller: 'TripSearchCardController',
5375        link: function (scope, element, attrs, controllers) {
5376            scope.CONFIG = CONFIG;
5377            scope.session = vSession;
5378            scope.globalModalShow = $rootScope.globalModalShow;
5379            scope.$watch('carpoolPrompt', function (value) {
5380                $log.debug('carpoolPrompt changed', value);
5381                if (value) {
5382                    scope.tripsearch = value.clone();
5383                }
5384                else {
5385                    scope.tripsearch = undefined;
5386                }
5387            });
5388        },
5389    };
5390});
5391appDirectives.directive('scoopCarpoolPrompt', function ($log, $rootScope, vSession, CONFIG) {
5392    $log = $log.getInstance('scoop-carpool-prompt');
5393    return {
5394        restrict: 'EA',
5395        templateUrl: '/templates/tripplan/results/scoopCarpoolPrompt.html',
5396        scope: {
5397            scoopCarpoolPrompt: '=',
5398        },
5399        controller: 'TripSearchCardController',
5400        link: function (scope, element, attrs, controllers) {
5401            scope.CONFIG = CONFIG;
5402            scope.session = vSession;
5403            scope.globalModalShow = $rootScope.globalModalShow;
5404            scope.$watch('scoopCarpoolPrompt', function (value) {
5405                $log.debug('scoopCarpoolPrompt changed', value);
5406                if (value) {
5407                    scope.tripsearch = value.clone();
5408                }
5409                else {
5410                    scope.tripsearch = undefined;
5411                }
5412            });
5413        },
5414    };
5415});
5416appDirectives.directive('vanpoolPrompt', function ($log, $rootScope, vSession, CONFIG) {
5417    $log = $log.getInstance('vanpool-prompt');
5418    return {
5419        restrict: 'EA',
5420        templateUrl: '/templates/tripplan/results/VanpoolPrompt.html',
5421        scope: {
5422            vanpoolPrompt: '=',
5423        },
5424        controller: 'TripSearchCardController',
5425        link: function (scope, element, attrs, controllers) {
5426            scope.CONFIG = CONFIG;
5427            scope.session = vSession;
5428            scope.globalModalShow = $rootScope.globalModalShow;
5429            scope.$watch('vanpoolPrompt', function (value) {
5430                $log.debug('vanpoolPrompt changed', value);
5431                if (value) {
5432                    scope.tripsearch = value.clone();
5433                }
5434                else {
5435                    scope.tripsearch = undefined;
5436                }
5437            });
5438        },
5439    };
5440});
5441appDirectives.directive('saveTripToast', function ($log, $rootScope, vSession, SessionUserDataService, Dialogs, CONFIG) {
5442    $log = $log.getInstance('save-trip-toast');
5443    return {
5444        restrict: 'EA',
5445        templateUrl: '/templates/tripplan/save-trip-toast.html',
5446        scope: {
5447            relatedSearch: '=',
5448            bikepool: '=',
5449            carpool: '=',
5450        },
5451        link: function ($scope, element, attrs, controllers) {
5452            $scope.CONFIG = CONFIG;
5453            $scope.session = vSession;
5454            $scope.globalModalShow = $rootScope.globalModalShow;
5455            $scope.createTrip = function (carpool, bikepool) {
5456                carpool = carpool === null ? false : carpool;
5457                bikepool = bikepool === null ? false : bikepool;
5458                var tripplan = {
5459                    tripPreferences: { bikepool: bikepool, carpool: carpool },
5460                };
5461                tripplan.from = $scope.relatedSearch.from;
5462                tripplan.to = $scope.relatedSearch.to;
5463                if ($scope.$parent.eventId)
5464                    tripplan.relatedEvent = $scope.$parent.eventId;
5465                var onCreateSuccess = function (tripplan) {
5466                    $log.debug('editTripplan', 'NEW', 'SUCCESS', tripplan);
5467                    $scope.tripplan = tripplan;
5468                    SessionUserDataService.updateTripplans();
5469                };
5470                var onCreateFault = function (error) {
5471                    $log.error('editTripplan', 'NEW', 'ERROR', error);
5472                    Dialogs.alert('Oops, we encountered a problem saving your trip.');
5473                };
5474                if (vSession.user) {
5475                    vSession.user
5476                        .post('tripplans', tripplan)
5477                        .then(onCreateSuccess, onCreateFault);
5478                }
5479                else {
5480                    return $rootScope.globalModalShow('account.login');
5481                }
5482            };
5483            $scope.hide = function () {
5484                $scope.$parent.showSaveTripToast = false;
5485            };
5486        },
5487    };
5488});
5489appDirectives.directive('tripplanEdit', function ($log, CONFIG) {
5490    $log = $log.getInstance('tripplan-edit directive');
5491    return {
5492        restrict: 'EA',
5493        scope: {
5494            tripplanEdit: '=',
5495            tripplanUser: '=?',
5496        },
5497        template: '<div v-modal="/templates/tripplan/favorite/edit.html" modal-visible="tripplan"></div>',
5498        link: function (scope, element, attrs, controllers) {
5499            scope.CONFIG = CONFIG;
5500            scope.tripplan = undefined;
5501            scope.$watch('tripplanEdit', function (value, oldValue) {
5502                $log.debug('tripplanEdit changed', value, oldValue);
5503                scope.tripplan = value;
5504                if (!!value &&
5505                    angular.isDefined(value.shared) &&
5506                    angular.isDefined(value.shared.public)) {
5507                    scope.sharedWith = !!value.shared.public
5508                        ? 'everyone'
5509                        : value.shared.networks.length
5510                            ? 'networks'
5511                            : 'noone';
5512                }
5513            });
5514        },
5515    };
5516});
5517appDirectives.directive('tripplanCard', function ($log, $rootScope, vSession, CONFIG) {
5518    $log = $log.getInstance('tripplan-card');
5519    return {
5520        restrict: 'EA',
5521        templateUrl: '/templates/tripplan/card.html',
5522        scope: {
5523            tripplanCard: '=',
5524        },
5525        controller: 'TripplanViewController',
5526        link: function (scope, element, attrs, controllers) {
5527            scope.CONFIG = CONFIG;
5528            scope.$watch('tripplanCard', function (value) {
5529                $log.debug('tripplanCard changed', value);
5530                if (value) {
5531                    scope.tripplan = value;
5532                }
5533                else {
5534                    scope.tripplan = undefined;
5535                }
5536                if (scope.tripplan.relatedEvent &&
5537                    _.isObject(scope.tripplan.relatedEvent) &&
5538                    scope.tripplan.relatedEvent.hasOwnProperty('_id')) {
5539                    scope.event = scope.tripplan.relatedEvent;
5540                }
5541            });
5542        },
5543    };
5544});
5545appDirectives.directive('carpoolResult', function (SessionUserDataService, CarpoolContactService, $log, vSession) {
5546    $log = $log.getInstance('carpool-result');
5547    return {
5548        restrict: 'EA',
5549        link: function (scope, element, attrs, controllers) {
5550            scope.session = vSession;
5551            scope.lastContacted = undefined;
5552            scope.relatedMessages = [];
5553            scope.sendMessage = function (message) {
5554                $log.debug('sendMessage(message)', message);
5555                CarpoolContactService.sendCarpoolMessage(scope.carpool, message, 'carpool');
5556            };
5557            scope.sessionUserData = SessionUserDataService;
5558            scope.$watchCollection('sessionUserData.carpoolmessages', function (value) {
5559                if (value && value.length && scope.carpool) {
5560                    scope.lastContacted =
5561                        CarpoolContactService.getLastContacted(value);
5562                    scope.relatedMessages =
5563                        CarpoolContactService.getCarpoolMessages(value);
5564                }
5565            });
5566            scope.$watch('carpool', function (value) {
5567                if (value) {
5568                    scope.lastContacted = CarpoolContactService.getLastContacted(value);
5569                    scope.relatedMessages =
5570                        CarpoolContactService.getCarpoolMessages(value);
5571                }
5572                else {
5573                    scope.lastContacted = undefined;
5574                    scope.relatedMessages = [];
5575                }
5576            });
5577        },
5578    };
5579});
5580appDirectives.directive('bikepoolResult', function (SessionUserDataService, CarpoolContactService, $log, vSession) {
5581    $log = $log.getInstance('bikepool-result');
5582    return {
5583        restrict: 'EA',
5584        link: function (scope, element, attrs, controllers) {
5585            scope.session = vSession;
5586            scope.lastContacted = undefined;
5587            scope.relatedMessages = [];
5588            scope.sendMessage = function (message) {
5589                $log.debug('sendMessage(message)', message);
5590                CarpoolContactService.sendCarpoolMessage(scope.bikepool, message, 'bikepool');
5591            };
5592            scope.sessionUserData = SessionUserDataService;
5593            scope.$watchCollection('sessionUserData.carpoolmessages', function (value) {
5594                if (value && value.length && scope.bikepool) {
5595                    scope.lastContacted =
5596                        CarpoolContactService.getLastContacted(value);
5597                    scope.relatedMessages =
5598                        CarpoolContactService.getCarpoolMessages(value);
5599                }
5600            });
5601            scope.$watch('bikepool', function (value) {
5602                if (value) {
5603                    scope.lastContacted = CarpoolContactService.getLastContacted(value);
5604                    scope.relatedMessages =
5605                        CarpoolContactService.getCarpoolMessages(value);
5606                }
5607                else {
5608                    scope.lastContacted = undefined;
5609                    scope.relatedMessages = [];
5610                }
5611            });
5612        },
5613    };
5614});
5615appDirectives.directive('poolResult', function (SessionUserDataService, CarpoolContactService, $log, vSession) {
5616    $log = $log.getInstance('pool-result');
5617    return {
5618        restrict: 'EA',
5619        link: function (scope, element, attrs, controllers) {
5620            scope.session = vSession;
5621            scope.lastContacted = undefined;
5622            scope.relatedMessages = [];
5623            scope.sendMessage = function (message) {
5624                $log.debug('sendMessage(message)', message);
5625                CarpoolContactService.sendCarpoolMessage(scope.pooldata, message, scope.pooldata.mode);
5626            };
5627            scope.sessionUserData = SessionUserDataService;
5628            scope.$watchCollection('sessionUserData.carpoolmessages', function (value) {
5629                if (value && value.length && scope.pooldata) {
5630                    scope.lastContacted =
5631                        CarpoolContactService.getLastContacted(value);
5632                    scope.relatedMessages =
5633                        CarpoolContactService.getCarpoolMessages(value);
5634                }
5635            });
5636            scope.$watch('pooldata', function (value) {
5637                if (value) {
5638                    scope.lastContacted = CarpoolContactService.getLastContacted(value);
5639                    scope.relatedMessages =
5640                        CarpoolContactService.getCarpoolMessages(value);
5641                }
5642                else {
5643                    scope.lastContacted = undefined;
5644                    scope.relatedMessages = [];
5645                }
5646            });
5647        },
5648    };
5649});
5650appDirectives.directive('vanpoolResult', function ($rootScope, SessionUserDataService, VanpoolContactService, $log, vSession) {
5651    $log = $log.getInstance('vanpool-result');
5652    return {
5653        restrict: 'EA',
5654        link: function (scope, element, attrs, controllers) {
5655            scope.session = vSession;
5656            scope.CONFIG = $rootScope.CONFIG;
5657            scope.sendMessage = function (message) {
5658                $log.debug('sendMessage(message)', message);
5659                VanpoolContactService.sendVanpoolMessage(scope.vanpool, message);
5660            };
5661            scope.sessionUserData = SessionUserDataService;
5662        },
5663    };
5664});
5665appDirectives.component('vanpoolList', {
5666    bindings: {
5667        vanpools: '<',
5668    },
5669    templateUrl: '/templates/vanpool/vanpool-list.html',
5670});
5671appDirectives.component('vanpoolCard', {
5672    bindings: {
5673        vanpool: '<',
5674    },
5675    templateUrl: '/templates/vanpool/vanpool-card.html',
5676});
5677appDirectives.directive('clipCopy', function ($window, $timeout, Clipboard) {
5678    return {
5679        restrict: 'A',
5680        scope: {
5681            clipCopy: '&',
5682            innerText: '@',
5683        },
5684        link: function ($scope, $element, attrs) {
5685            var innerText = ($scope.innerText = $scope.innerText || 'Copy'), clipboard = null;
5686            $scope.$watch($scope.clipCopy, function () {
5687                if (getValue()) {
5688                    init();
5689                }
5690            });
5691            function init() {
5692                $timeout(attachClipboardToElement);
5693                $scope.$on('new-slug', function ($e, slug) {
5694                    $scope.clipCopy = slug.fullURL;
5695                    $timeout(attachClipboardToElement);
5696                });
5697            }
5698            function attachClipboardToElement() {
5699                $($element[0]).html(innerText);
5700                clipboard = getClipboard($element[0], getValue());
5701                bindEventsTo(clipboard);
5702            }
5703            function getClipboard(element, value) {
5704                return new Clipboard(element, {
5705                    text: function (trigger) {
5706                        return value;
5707                    },
5708                });
5709            }
5710            function getValue() {
5711                return angular.isString($scope.clipCopy)
5712                    ? $scope.clipCopy
5713                    : $scope.$eval($scope.clipCopy);
5714            }
5715            function bindEventsTo(clipboard) {
5716                clipboard.on('success', success);
5717                clipboard.on('error', function (e) {
5718                });
5719            }
5720            $scope.$on('$destroy', cleanup);
5721            function cleanup() {
5722                if (clipboard) {
5723                    clipboard.destroy();
5724                }
5725            }
5726            function success(e) {
5727                e.trigger.innerText = 'Copied!';
5728                $timeout(function () {
5729                    $($element[0]).html(innerText);
5730                    e.clearSelection();
5731                }, 300);
5732            }
5733        },
5734    };
5735});
5736appDirectives.directive('tripplanWidget', function (VTMOSessionService, VTMOEventService, TripSearchService, TripPlanService, $state, LocationService) {
5737    var opts = {
5738        restrict: 'EA',
5739        replace: true,
5740        templateUrl: '/templates/tripplan/widget.html',
5741        link: function (scope, elm, attr, controller) {
5742            scope.session = VTMOSessionService.getCurrentSession();
5743            scope.$watch('session.status', function (value) {
5744                TripSearchService.updateHistory();
5745                TripPlanService.updateFavorites();
5746            });
5747            scope.history = TripSearchService.getHistory();
5748            scope.favorites = TripPlanService.getFavorites();
5749            scope.activeFavorite = undefined;
5750            scope.openSearchModal = function (search) {
5751                var savedFavorite = TripPlanService.hasFavorite(search.from, search.to);
5752                if (!savedFavorite) {
5753                    TripPlanService.createFavoriteFromSearch(search).then(function (favorite) {
5754                        scope.activeFavorite = favorite;
5755                    }, function (error) {
5756                        scope.activeFavorite = TripPlanService.newPlan();
5757                    });
5758                }
5759                else {
5760                    scope.activeFavorite = angular.copy(savedFavorite);
5761                }
5762            };
5763            scope.openFavoriteModal = function (savedFavorite) {
5764                scope.confirmRemove = false;
5765                scope.activeFavorite = angular.copy(savedFavorite);
5766                VTMOEventService.broadcast('AnalyticsEvent', {
5767                    category: 'Trip Planner',
5768                    action: 'Favorite Modal Opened',
5769                });
5770            };
5771            scope.closeFavoriteModal = function () {
5772                scope.confirmRemove = false;
5773                scope.activeFavorite = undefined;
5774            };
5775            scope.showHistorySearchResults = function (history, reverse) {
5776                reverse = reverse == null ? false : reverse;
5777                var search = {
5778                    from: LocationService.locationToString(history.from),
5779                    to: LocationService.locationToString(history.to),
5780                    date: history.date,
5781                    time: history.time,
5782                };
5783                if (reverse) {
5784                    var f = search.from, t = search.to;
5785                    search.from = t;
5786                    search.to = f;
5787                }
5788                $state.transitionTo('dashboard.plan', search);
5789                VTMOEventService.broadcast('AnalyticsEvent', {
5790                    category: 'Trip Planner',
5791                    action: 'Search from History',
5792                    label: 'Reverse: ' + reverse,
5793                });
5794            };
5795            scope.showFavoriteSearchResults = function (favorite, reverse) {
5796                reverse = reverse == null ? false : reverse;
5797                var search = {
5798                    from: LocationService.locationToString(favorite.from),
5799                    to: LocationService.locationToString(favorite.to),
5800                    date: moment(new Date()).format('YYYY-MM-DD'),
5801                    time: moment(new Date()).format('hh:mm A'),
5802                };
5803                if (reverse) {
5804                    var f = search.from, t = search.to;
5805                    search.from = t;
5806                    search.to = f;
5807                }
5808                $state.transitionTo('dashboard.plan', search);
5809                VTMOEventService.broadcast('AnalyticsEvent', {
5810                    category: 'Trip Planner',
5811                    action: 'Search from Favorites',
5812                    label: 'Reverse: ' + reverse,
5813                });
5814            };
5815            scope.isSearchFavorite = function (search) {
5816                var savedFavorite = TripPlanService.hasFavorite(search.from, search.to);
5817                return savedFavorite !== false;
5818            };
5819            scope.saveFavorite = function (plan) {
5820                TripPlanService.save(plan).then(function (plan) {
5821                    scope.activeFavorite = undefined;
5822                    VTMOEventService.broadcast('AnalyticsEvent', {
5823                        category: 'Trip Planner',
5824                        action: 'Favorite Created',
5825                    });
5826                }, function (err) {
5827                    scope.activeFavorite = undefined;
5828                });
5829            };
5830            scope.removeFavorite = function (plan) {
5831                TripPlanService.destroy(plan).then(function () {
5832                    scope.activeFavorite = undefined;
5833                    VTMOEventService.broadcast('AnalyticsEvent', {
5834                        category: 'Trip Planner',
5835                        action: 'Favorite Removed',
5836                    });
5837                }, function (err) {
5838                    scope.activeFavorite = undefined;
5839                });
5840            };
5841        },
5842    };
5843    return opts;
5844});
5845appDirectives.directive('networkSelect', function (vNetworks, $log, $timeout, $sanitize, $filter) {
5846    $log = $log.getInstance('network-select');
5847    return {
5848        restrict: 'EA',
5849        scope: {
5850            selectedNetworks: '=?',
5851            selectedNetworkIds: '=?',
5852            availableNetworks: '=?',
5853            maxSelectedNetworks: '@?',
5854        },
5855        link: function (scope, element, attrs) {
5856            scope.$watchCollection('selectedNetworks', function (value) {
5857                if (!value) {
5858                    scope.selectedNetworks = [];
5859                }
5860                else {
5861                    scope.selectedNetworkIds = _.map(value, '_id');
5862                }
5863            });
5864            scope.$watchCollection('selectedNetworkIds', function (value) {
5865                if (!value) {
5866                    scope.selectedNetworkIds = [];
5867                }
5868                else {
5869                    updateSelect2();
5870                }
5871            });
5872            scope.$watchCollection('availableNetworks', function (value) {
5873                if (!!value)
5874                    updateSelect2();
5875            });
5876            var select2Inited = false;
5877            function initSelect2() {
5878                $(element).on('change', function (e) {
5879                    if (e.val) {
5880                        var obj = $(e.target).select2('data');
5881                        scope.$apply(function () {
5882                            scope.selectedNetworks.push(obj.network);
5883                            $timeout(updateSelect2);
5884                        });
5885                    }
5886                });
5887                select2Inited = true;
5888            }
5889            function updateSelect2() {
5890                if (!select2Inited)
5891                    initSelect2();
5892                var networkData = [];
5893                _.forEach(scope.availableNetworks, function (net) {
5894                    if (!_.includes(scope.selectedNetworkIds, net._id)) {
5895                        networkData.push({
5896                            id: net._id,
5897                            text: net.name,
5898                            network: net,
5899                        });
5900                    }
5901                });
5902                $(element).select2({
5903                    data: networkData,
5904                    dropdownAutoWidth: true,
5905                    width: 'copy',
5906                    formatResult: function (net) {
5907                        var networkRendererHTML = '<p>' +
5908                            '<b><var networkName>' +
5909                            _.escape(net.network.name) +
5910                            '</var></b> ' +
5911                            '<small>(' +
5912                            net.network.type +
5913                            ')</small>' +
5914                            '</p>';
5915                        var parentNetworkNames = _.map(net.network.ancestors, 'name');
5916                        if (parentNetworkNames.length > 0) {
5917                            networkRendererHTML +=
5918                                "<p><small class='text-muted'><i><b isolate>Parent Network:</b><span notranslate> " +
5919                                    _.escape(parentNetworkNames.join(', ')) +
5920                                    '</span></i></small></p>';
5921                        }
5922                        if (net.network.description) {
5923                            networkRendererHTML +=
5924                                '<p><i><var description>' +
5925                                    $sanitize($filter('markdownToHTML')(net.network.description)) +
5926                                    '</var></i></p><hr />';
5927                        }
5928                        if (!net.network.description) {
5929                            networkRendererHTML += '<hr />';
5930                        }
5931                        return networkRendererHTML;
5932                    },
5933                });
5934                $(element).val(null);
5935            }
5936        },
5937    };
5938});
5939appDirectives.directive('multiNetworkSelect', function (vNetworks, $log, $timeout, $sanitize, $filter) {
5940    $log = $log.getInstance('multi-network-select');
5941    return {
5942        restrict: 'EA',
5943        scope: {
5944            selectedNetworks: '=?',
5945            selectedNetworkIds: '=?',
5946            availableNetworks: '=?',
5947        },
5948        link: function (scope, element, attrs) {
5949            $log.debug('link()', scope);
5950            var select2Inited = false;
5951            function initSelect2() {
5952                $log.debug('initSelect2()');
5953                $(element).on('change', function (e) {
5954                    if (e.val) {
5955                        var selections = $(e.target).select2('data');
5956                        scope.$apply(function () {
5957                            scope.selectedNetworks.length = 0;
5958                            scope.selectedNetworkIds.length = 0;
5959                            _.forEach(selections, function (selection) {
5960                                if (selection && selection.network) {
5961                                    scope.selectedNetworks.push(selection.network);
5962                                    scope.selectedNetworkIds.push(selection.network._id);
5963                                }
5964                            });
5965                            $timeout(updateSelect2);
5966                        });
5967                    }
5968                });
5969                select2Inited = true;
5970            }
5971            function updateSelect2() {
5972                $log.debug('updateSelect2()');
5973                if (!select2Inited)
5974                    initSelect2();
5975                var networkData = [];
5976                _.forEach(scope.availableNetworks, function (net) {
5977                    $log.debug('availableNetwork', net);
5978                    networkData.push({
5979                        id: net._id,
5980                        text: net.name,
5981                        network: net,
5982                    });
5983                });
5984                $log.debug('networkData', networkData);
5985                $(element).select2({
5986                    data: networkData,
5987                    multiple: true,
5988                    allowClear: true,
5989                    width: 'resolve',
5990                    dropdownAutoWidth: true,
5991                    formatResult: function (net) {
5992                        return ('<p><b>' +
5993                            _.escape(net.network.name) +
5994                            '</b> ' +
5995                            '<small>(' +
5996                            net.network.type +
5997                            ')</small></p>');
5998                    },
5999                });
6000                $(element).val(scope.selectedNetworkIds);
6001            }
6002            if (!scope.selectedNetworks)
6003                scope.selectedNetworks = [];
6004            if (!scope.selectedNetworkIds)
6005                scope.selectedNetworkIds = [];
6006            scope.$watchCollection('selectedNetworkIds', function (value) {
6007                $log.debug('selectedNetworkIds CHANGE', value);
6008                if (value)
6009                    updateSelect2();
6010            });
6011            scope.$watchCollection('availableNetworks', function (value) {
6012                $log.debug('availableNetworks CHANGE', value);
6013                if (value)
6014                    updateSelect2();
6015            });
6016            updateSelect2();
6017        },
6018    };
6019});
6020appDirectives.directive('scrollableContainer', function ($timeout, $q, $log) {
6021    return {
6022        link: function ($scope, $element, $attrs) {
6023            var scrollDelay = $attrs.hasOwnProperty('scrollDelay')
6024                ? parseInt($attrs.scrollDelay)
6025                : 0;
6026            var scrollOffset = parseInt($attrs.scrollOffset || 0);
6027            var scrollFunctionName = $attrs.scrollableContainer + 'ScrollToSelector';
6028            $log.debug('scrollable container - use $scope.' +
6029                scrollFunctionName +
6030                ' to scroll to jquery selector');
6031            var lastTarget;
6032            $scope[scrollFunctionName] = function (selector, requireDifferentTarget) {
6033                var deferred = $q.defer();
6034                $timeout(function () {
6035                    var containerOffset = $($element).offset();
6036                    var target = $(selector, $element)[0];
6037                    if (!target)
6038                        return deferred.reject();
6039                    if (requireDifferentTarget && target === lastTarget)
6040                        return deferred.reject();
6041                    var targetTop = $(target).position().top;
6042                    var offsetTop = $($element).scrollTop();
6043                    $($element).animate({
6044                        scrollTop: targetTop + offsetTop + scrollOffset,
6045                    });
6046                    lastTarget = target;
6047                    deferred.resolve(target);
6048                }, scrollDelay);
6049                return deferred.promise;
6050            };
6051        },
6052    };
6053});
6054appDirectives.directive('scrollTo', function ($log, $timeout) {
6055    $log = $log.getInstance('scroll-to directive');
6056    return {
6057        restrict: 'A',
6058        link: function (scope, element, attrs) {
6059            angular.element(element).on('click', function () {
6060                if (angular.isDefined(attrs['scrollToIf']) &&
6061                    !scope.$eval(attrs['scrollToIf']))
6062                    return;
6063                var bestTarget, target;
6064                var scrollToOffset = angular.isDefined(attrs['scrollToOffset'])
6065                    ? attrs['scrollToOffset']
6066                    : 0;
6067                var navbarFixedHeight = angular.element('.navbar-fixed-top').length
6068                    ? angular.element('.navbar-fixed-top').height()
6069                    : 0;
6070                $timeout(function () {
6071                    bestTarget =
6072                        attrs['scrollTo'] === 'this' ? element[0] : attrs['scrollTo'];
6073                    target = angular.element(bestTarget);
6074                    scrollToTarget(target);
6075                }, 300);
6076                function getScrollTopElement() {
6077                    $log.debug('************getScrollTopElement()');
6078                    if (document.compatMode !== 'CSS1Compat')
6079                        return 'body';
6080                    var html = document.documentElement;
6081                    var body = document.body;
6082                    var startingY = window.pageYOffset || body.scrollTop || html.scrollTop;
6083                    var newY = startingY + 1;
6084                    window.scrollTo(0, newY);
6085                    var element = html.scrollTop === newY ? 'html' : 'body';
6086                    window.scrollTo(0, startingY);
6087                    return element;
6088                }
6089                window.scrollTopElement =
6090                    window.scrollTopElement || getScrollTopElement();
6091                function scrollToTarget(target) {
6092                    if (target.length) {
6093                        var targetTop = target.offset().top;
6094                        $(window.scrollTopElement).animate({
6095                            scrollTop: targetTop - navbarFixedHeight - scrollToOffset,
6096                        });
6097                    }
6098                }
6099            });
6100        },
6101    };
6102});
6103appDirectives.directive('clusterMap', function ($rootScope, $timeout) {
6104    var config = $rootScope.CONFIG;
6105    return {
6106        restrict: 'A',
6107        scope: {
6108            clusterData: '=?',
6109            clusterFields: '=?',
6110            filter: '=?',
6111            visibleItems: '=?',
6112            selectedItems: '=?',
6113        },
6114        template: '<div style="width:50%; display:inline-block; height:300px"></div>',
6115        link: function (scope, element, attrs, ctrl) {
6116            var map = L.map($(element)[0], { zoomControl: false }
6116).setView([config.mapDefaultCenterPoint.lat, config.mapDefaultCenterPoint.lng], config.mapDefaultZoom);
6117            map.attributionControl.setPrefix('');
6118            map.addControl(L.control.zoom({ position: 'topright' }));
6119            var layerOptions = {
6120                maxZoom: 16,
6121                tileSize: 512,
6122                zoomOffset: -1,
6123                detectRetina: false,
6124                attribution: $scope.attribution ||
6125                    "© <a href='https://www.mapbox.com/map-feedback/'>Mapbox</a> © <a href='http://www.openstreetmap.org/copyright'>OpenStreetMap</a>",
6126            };
6127            function isRetinaDisplay() {
6128                if (window.matchMedia) {
6129                    var mq = window.matchMedia('only screen and (min--moz-device-pixel-ratio: 1.3), only screen and (-o-min-device-pixel-ratio: 2.6/2), only screen and (-webkit-min-device-pixel-ratio: 1.3), only screen  and (min-device-pixel-ratio: 1.3), only screen and (min-resolution: 1.3dppx)');
6130                    return (mq && mq.matches) || window.devicePixelRatio > 1;
6131                }
6132            }
6133            var RETINA = isRetinaDisplay() ? '@2x' : '';
6134            L.tileLayer('https://api.mapbox.com/styles/v1/' +
6135                config.mapboxId +
6136                '/tiles/512/{z}/{x}/{y}' +
6137                RETINA +
6138                '?access_token=' +
6139                config.mapboxPublicToken, {
6140                maxZoom: 20,
6141                detectRetina: false,
6142                tileSize: 512,
6143                zoomOfsset: -1,
6144                attribution: config.mapAttribution,
6145            }).addTo(map);
6146            var routes = new L.LayerGroup();
6147            map.addLayer(routes);
6148            var markers = new L.MarkerClusterGroup();
6149            map.addLayer(markers);
6150            var debouncedUpdate = _.debounce(updateVisibleAttribute, 200);
6151            map.on('move', function () {
6152                debouncedUpdate();
6153                $timeout(function () {
6154                    scope.$apply();
6155                }, 250);
6156            });
6157            scope.$watchCollection('clusterData', function (newVal, oldVal) {
6158                if (newVal) {
6159                    markers.clearLayers();
6160                    createClusters(_.sortBy(newVal, 'created'));
6161                    updateVisibleAttribute();
6162                }
6163            });
6164            var aMarkerIcon = L.icon({
6165                iconUrl: '/img/marker-a.svg',
6166                iconSize: [44, 72],
6167                shadowSize: [50, 29],
6168                iconAnchor: [22, 72],
6169                shadowAnchor: [2, 27],
6170                popupAnchor: [-3, -76],
6171            });
6172            var bMarkerIcon = L.icon({
6173                iconUrl: '/img/marker-b.svg',
6174                iconSize: [44, 72],
6175                shadowSize: [50, 29],
6176                iconAnchor: [22, 72],
6177                shadowAnchor: [2, 27],
6178                popupAnchor: [-3, -76],
6179            });
6180            function createClusters(data) {
6181                _.forEach(data, function (tripplan) {
6182                    var tripplanContent = getPopupContent(tripplan);
6183                    var from = tripplan.from;
6184                    var to = tripplan.to;
6185                    var amarker = new L.Marker(from, {
6186                        icon: aMarkerIcon,
6187                        tripplan: tripplan,
6188                    });
6189                    amarker.bindPopup(tripplanContent);
6190                    markers.addLayer(amarker);
6191                    var bmarker = new L.Marker(to, {
6192                        icon: bMarkerIcon,
6193                        tripplan: tripplan,
6194                    });
6195                    bmarker.bindPopup(tripplanContent);
6196                    markers.addLayer(bmarker);
6197                });
6198            }
6199            function getPopupContent(tripplan) {
6200                var content = [
6201                    '<table>',
6202                    "<tr><td colspan='2'><b>Trip Plan</b></td></tr>",
6203                ];
6204                try {
6205                    content.push("<tr><td><b>From</b></td><td><a href='javascript:zoomTo({lat:" +
6206                        tripplan.from.lat +
6207                        ',lng:' +
6208                        tripplan.from.lng +
6209                        "})'>" +
6210                        tripplan.from.label +
6211                        '</a></td></tr>');
6212                    content.push("<tr><td><b>To</b></td><td><a href='javascript:zoomTo({lat:" +
6213                        tripplan.to.lat +
6214                        ',lng:' +
6215                        tripplan.to.lng +
6216                        "})'>" +
6217                        tripplan.to.label +
6218                        '</a></td></tr>');
6219                    if (tripplan.user) {
6220                        content.push("<tr><td><b>Posted By</b></td><td><a href='mailto:" +
6221                            tripplan.user.email +
6222                            "'>" +
6223                            tripplan.user.firstName +
6224                            ' ' +
6225                            tripplan.user.lastName +
6226                            '</a></td></tr>');
6227                    }
6228                    var shared = tripplan.shared.public == true
6229                        ? 'Public'
6230                        : tripplan.shared.networks.length
6231                            ? tripplan.shared.networks.length + ' Networks'
6232                            : 'Not Shared';
6233                    content.push('<tr><td><b>Shared?</b></td><td>' + shared + '</td></tr>');
6234                }
6235                catch (error) {
6236                    content.push("<tr><td colspan='2'> Problem processing triplog. </td></tr>");
6237                }
6238                content.push('</table>');
6239                return content.join('');
6240            }
6241            scope.$parent.zoomTo = window.zoomTo = function (pt) {
6242                map.setView({ lat: pt.lat, lng: pt.lng });
6243            };
6244            scope.$parent.showItem = function (item) {
6245                map.fitBounds([
6246                    { lat: item.from.lat, lng: item.from.lng },
6247                    { lat: item.to.lat, lng: item.to.lng },
6248                ], { padding: [100, 100] });
6249            };
6250            scope.$parent.showRoute = function (item) {
6251                routes.clearLayers();
6252                var from = item.from;
6253                var to = item.to;
6254                var amarker = new L.Marker(from, { icon: aMarkerIcon });
6255                routes.addLayer(amarker);
6256                var bmarker = new L.Marker(to, { icon: bMarkerIcon });
6257                routes.addLayer(bmarker);
6258                routes.addLayer(L.polyline([from, to], { color: 'blue', fillOpacity: 0.11 }).addTo(map));
6259            };
6260            scope.$parent.hideRoutes = function () {
6261                routes.clearLayers();
6262            };
6263            function updateVisibleAttribute() {
6264                var bounds = map.getBounds();
6265                var updateFn = function () {
6266                    _.forEach(scope.clusterData, function (tripplan) {
6267                        if (!tripplan.from || !tripplan.to) {
6268                            tripplan.visible = false;
6269                            return;
6270                        }
6271                        var from = new L.LatLng(tripplan.from.lat, tripplan.from.lng);
6272                        var to = new L.LatLng(tripplan.to.lat, tripplan.to.lng);
6273                        if (bounds.contains(from) || bounds.contains(to)) {
6274                            tripplan.visible = true;
6275                        }
6276                        else {
6277                            tripplan.visible = false;
6278                        }
6279                    });
6280                };
6281                if (scope.$$phase != null) {
6282                    scope.$apply(updateFn);
6283                }
6284                else {
6285                    updateFn();
6286                }
6287            }
6288            $(window).resize(function () {
6289                'use strict';
6290                resize();
6291            });
6292            function resize() {
6293                'use strict';
6294                $(element).css('width', $('.parent-view').width());
6295                $(element).css('height', $('.parent-view').height());
6296                map.invalidateSize();
6297            }
6298            $timeout(function () {
6299                resize();
6300            });
6301        },
6302    };
6303});
6304appDirectives.directive('shortUrlEdit', function (ShortURL, $rootScope) {
6305    return {
6306        restrict: 'EA',
6307        templateUrl: '/templates/shorturl/edit.html',
6308        require: '?^form',
6309        scope: {
6310            shortUrlId: '@',
6311        },
6312        link: function ($scope, $element, attrs, formCtrl) {
6313            if (formCtrl) {
6314                formCtrl.$removeControl(formCtrl.shortURL);
6315            }
6316            $scope.$watch('shortUrlId', function (newVal, oldVal) {
6317                if (!newVal)
6318                    return;
6319                ShortURL.getShortURL(newVal).then(function (shortUrl) {
6320                    $scope.shortUrl = shortUrl;
6321                });
6322            });
6323            $scope.cancelSlug = function () {
6324                $scope.newSlug = null;
6325            };
6326            $scope.updateSlug = function () {
6327                if ($scope.newSlug === $scope.shortUrl.slug) {
6328                    $scope.newSlug = null;
6329                    return;
6330                }
6331                $scope.shortUrl
6332                    .updateSlug($scope.newSlug)
6333                    .then(function (updatedShortURL) {
6334                    ShortURL.getShortURL(updatedShortURL._id).then(function (shortURL) {
6335                        $scope.shortUrl = shortURL;
6336                        $rootScope.$broadcast('new-slug', shortURL);
6337                    });
6338                    $scope.newSlug = null;
6339                });
6340            };
6341        },
6342    };
6343});
6344appDirectives.directive('clickToCopy', function (URLService) {
6345    return {
6346        restrict: 'EA',
6347        templateUrl: '/templates/formfields/clickToCopy.html',
6348        scope: {
6349            copyText: '@',
6350            relativeUrl: '@',
6351            hideUrl: '@?',
6352        },
6353        link: function ($scope, $element, attrs) {
6354            $scope.$watch('relativeUrl', function (newVal) {
6355                if (newVal) {
6356                    $scope.copyText = URLService.getRelativeUrl(newVal);
6357                }
6358            });
6359        },
6360    };
6361});
6362appDirectives.directive('copyToClipboard', function (ShortURL, $timeout, Clipboard) {
6363    return {
6364        restrict: 'EA',
6365        template: '<div class="input-group"><input type="text" readonly id="item_{{$id}}" class="form-control disabled" value="{{shortUrl.fullURL}}"><span class="input-group-btn"><button class="btn btn-default" type="button" data-clipboard-action="copy" data-clipboard-target="#item_{{$id}}">{{innerText}}</button></span></div>',
6366        scope: {
6367            shortUrlId: '@',
6368            innerText: '@',
6369            hideUrl: '@?',
6370        },
6371        link: function ($scope, $element, attrs) {
6372            var innerText = ($scope.innerText = $scope.innerText || 'Copy');
6373            var clipboard = new Clipboard();
6374            $scope.$watch('shortUrlId', resolveUrl);
6375            $element.on('$destroy', cleanup);
6376            clipboard.on('success', success);
6377            function cleanup() {
6378                clipboard.destroy();
6379            }
6380            function success(e) {
6381                e.trigger.innerText = 'Copied!';
6382                $timeout(function () {
6383                    e.trigger.innerText = innerText;
6384                    e.clearSelection();
6385                }, 300);
6386            }
6387            function resolveUrl(newVal, oldVal) {
6388                if (!newVal)
6389                    return;
6390                ShortURL.getShortURL(newVal).then(function (shortUrl) {
6391                    $scope.shortUrl = shortUrl;
6392                });
6393            }
6394        },
6395    };
6396});
6397appDirectives.directive('shortUrlView', function (ShortURL) {
6398    return {
6399        restrict: 'EA',
6400        templateUrl: '/templates/shorturl/view.html',
6401        scope: {
6402            shortUrlId: '@',
6403            hideUrl: '@?',
6404            fullUrl: '=?',
6405        },
6406        link: function ($scope, $element, attrs) {
6407            $scope.$watch('shortUrlId', function (newVal, oldVal) {
6408                if (!newVal)
6409                    return;
6410                ShortURL.getShortURL(newVal).then(function (shortUrl) {
6411                    $scope.shortUrl = shortUrl;
6412                    $scope.fullUrl = shortUrl.fullURL;
6413                });
6414            });
6415        },
6416    };
6417});
6418appDirectives.directive('copyTextBtn', function (ShortURL, Clipboard, $timeout) {
6419    return {
6420        restrict: 'E',
6421        transclude: true,
6422        template: '<button class="team-invite fake-last-child" data-clipboard-text="{{shortUrl.fullURL}}"><i class="fa fa-paper-plane"></i>{{innerText}}</button>',
6423        scope: {
6424            shortUrlId: '@',
6425            innerText: '@',
6426            hideUrl: '@?',
6427        },
6428        link: function ($scope, $element, attrs) {
6429            var innerText = ($scope.innerText =
6430                $scope.innerText || 'Copy Team Url');
6431            var clipboard = new Clipboard('.team-invite');
6432            $scope.$watch('shortUrlId', resolveUrl);
6433            $element.on('$destroy', cleanup);
6434            clipboard.on('success', success);
6435            function cleanup() {
6436                clipboard.destroy();
6437            }
6438            function success(e) {
6439                e.trigger.innerText = 'Copied!';
6440                $timeout(function () {
6441                    e.trigger.innerText = innerText;
6442                    e.clearSelection();
6443                }, 300);
6444            }
6445            function resolveUrl(newVal, oldVal) {
6446                if (!newVal)
6447                    return;
6448                ShortURL.getShortURL(newVal).then(function (shortUrl) {
6449                    $scope.shortUrl = shortUrl;
6450                });
6451            }
6452        },
6453    };
6454});
6455appDirectives.directive('bindUnsafeHtml', function ($compile) {
6456    return function (scope, element, attrs) {
6457        scope.$watch(function (scope) {
6458            return scope.$eval(attrs.bindUnsafeHtml);
6459        }, function (value) {
6460            element.html(value);
6461            $compile(element.contents())(scope);
6462        });
6463    };
6464});
6465appDirectives.directive('bootstrapTooltip', function ($log, $timeout) {
6466    $log = $log.getInstance('bootstrap-tooltip');
6467    return function (scope, element, attrs) {
6468        attrs.$observe('title', function (title) {
6469            $log.debug('tooltip registered', element);
6470            element.tooltip();
6471        });
6472        element.on('$destroy', function () {
6473            element.tooltip('destroy');
6474            $log.debug('tooltip destroyed');
6475            delete attrs.$$observers['title'];
6476        });
6477    };
6478});
6479appDirectives.directive('vtmoLink', function ($rootScope, CONFIG) {
6480    var defaultLanguage = CONFIG.localize && CONFIG.localize.targetLanguage
6481        ? CONFIG.localize.targetLanguage
6482        : 'en';
6483    function applyLink(element, linkOptions) {
6484        var keys = _.keys(linkOptions);
6485        var handleClick = function (event) {
6486            event.preventDefault();
6487            $rootScope.globalModalShow(linkOptions.template);
6488        };
6489        $(element).off('click', handleClick);
6490        if (_.includes(keys, 'url')) {
6491            $(element).attr('href', linkOptions.url);
6492            if (linkOptions.target)
6493                $(element).attr('target', linkOptions.target);
6494        }
6495        else if (_.includes(keys, 'src')) {
6496            $(element).attr('src', linkOptions.src);
6497        }
6498        else if (_.includes(keys, 'template')) {
6499            $(element).attr('href', '');
6500            $(element).on('click', handleClick);
6501        }
6502        else {
6503            throw 'Invalid vtmo-link attribute';
6504        }
6505        $(element).css('cursor', 'pointer');
6506    }
6507    return function ($scope, element, attrs) {
6508        var vtmoLink = $scope.$eval(attrs.vtmoLink);
6509        if (!_.isObject(vtmoLink))
6510            throw 'Invalid vtmo-link attribute';
6511        var keys = _.keys(vtmoLink);
6512        if (_.includes(keys, 'url') || _.includes(keys, 'template')) {
6513            applyLink(element, vtmoLink);
6514        }
6515        else if (_.includes(keys, defaultLanguage)) {
6516            $scope.$watch('Localize.getLanguage()', function (localizeLang) {
6517                var langKey = localizeLang || defaultLanguage;
6518                if (!vtmoLink.hasOwnProperty(langKey))
6519                    throw 'Invalid vtmo-link object, missing language:' + langKey;
6520                var localizedLinkOptions = vtmoLink[langKey];
6521                applyLink(element, localizedLinkOptions);
6522            });
6523        }
6524        else {
6525            throw 'Invalid vtmo-link attribute';
6526        }
6527    };
6528});
6529appDirectives.directive('eatClick', function eatClick($log) {
6530    $log = $log.getInstance('directive:eatClick');
6531    return {
6532        restrict: 'A',
6533        link: function ($scope, element, attrs, controller) {
6534            $log.debug('Initialized on:', element);
6535            $(element).click(function (event) {
6536                $log.debug('element:', element, 'event:', event);
6537                event.stopPropagation();
6538                event.preventDefault();
6539                event.cancelBubble = true;
6540                event.returnValue = false;
6541            });
6542        },
6543    };
6544});
6545appDirectives.directive('ngContent', function ($log) {
6546    $log = $log.getInstance('directive:ngContent');
6547    return {
6548        restrict: 'A',
6549        link: function ($scope, $el, $attrs) {
6550            var cancelWatch = $scope.$watch($attrs.ngContent, function (value) {
6551                $el.attr('content', value);
6552                $log.debug($attrs.name, value);
6553                if (value)
6554                    cancelWatch();
6555            });
6556        },
6557    };
6558});
6559appDirectives.directive('matchHeaders', function ($timeout) {
6560    return {
6561        restrict: 'A',
6562        link: function ($scope, iElm, iAttrs, controller) {
6563            $timeout(function () {
6564                var $theseColumns = $(iElm).find('tbody tr:first td');
6565                var $theseHeaders = $($(iElm).attr('match-headers')).find('thead tr th');
6566                var sampleValue = currentSampleWidths($theseColumns);
6567                $scope.$watch(function () {
6568                    return (currentSampleWidths($theseColumns) ||
6569                        currentSampleTextLength($theseColumns.parent()));
6570                }, function () {
6571                    $timeout(function () {
6572                        adjustHeaderWidths($theseHeaders, $theseColumns);
6573                    }, 150);
6574                });
6575                function currentSampleWidths($elements) {
6576                    var sampleThis = $elements.length - ($elements.length > 3 ? 2 : 1);
6577                    return ($elements.eq(0).innerWidth() + $elements.eq(sampleThis).innerWidth());
6578                }
6579                function currentSampleTextLength($element) {
6580                    return $element.text().length;
6581                }
6582                function adjustHeaderWidths() {
6583                    var $columns = $(iElm).find('tbody tr:first td');
6584                    var $headers = $($(iElm).attr('match-headers')).find('thead tr th');
6585                    $headers
6586                        .parentsUntil('table')
6587                        .add($headers.closest('table'))
6588                        .each(function () {
6589                        $(this).width($columns.closest('table').width());
6590                    });
6591                    for (var i = $headers.length - 1; i >= 0; i--) {
6592                        var $th = $headers.eq(i);
6593                        var $td = $columns.eq(i);
6594                        $th.innerWidth($td.innerWidth());
6595                    }
6596                }
6597            }, 5);
6598        },
6599    };
6600});
6601appDirectives.directive('glyphicon', function () {
6602    return {
6603        restrict: 'C',
6604        link: function ($scope, iElm, iAttrs, controller) {
6605            var classList = iElm.attr('class').split(/\s+/);
6606            angular.forEach(classList, function (className) {
6607                if (className.indexOf('glyphicon') > -1) {
6608                    iElm.removeClass(className);
6609                    var newClassName = className.replace('glyphicon', 'fa');
6610                    iElm.addClass(newClassName);
6611                }
6612            });
6613        },
6614    };
6615});
6616appDirectives.directive('checklistModel', function ($parse, $compile) {
6617    function contains(arr, item, comparator) {
6618        if (angular.isArray(arr)) {
6619            for (var i = arr.length; i--;) {
6620                if (comparator(arr[i], item)) {
6621                    return true;
6622                }
6623            }
6624        }
6625        return false;
6626    }
6627    function add(arr, item, comparator) {
6628        arr = angular.isArray(arr) ? arr : [];
6629        if (!contains(arr, item, comparator)) {
6630            arr.push(item);
6631        }
6632        return arr;
6633    }
6634    function remove(arr, item, comparator) {
6635        if (angular.isArray(arr)) {
6636            for (var i = arr.length; i--;) {
6637                if (comparator(arr[i], item)) {
6638                    arr.splice(i, 1);
6639                    break;
6640                }
6641            }
6642        }
6643        return arr;
6644    }
6645    function postLinkFn(scope, elem, attrs) {
6646        $compile(elem)(scope);
6647        var getter = $parse(attrs.checklistModel);
6648        var setter = getter.assign;
6649        var checklistChange = $parse(attrs.checklistChange);
6650        var value = $parse(attrs.checklistValue)(scope.$parent);
6651        var comparator = angular.equals;
6652        if (attrs.hasOwnProperty('checklistComparator')) {
6653            comparator = $parse(attrs.checklistComparator)(scope.$parent);
6654        }
6655        scope.$watch('checked', function (newValue, oldValue) {
6656            if (newValue === oldValue) {
6657                return;
6658            }
6659            var current = getter(scope.$parent);
6660            if (newValue === true) {
6661                setter(scope.$parent, add(current, value, comparator));
6662            }
6663            else {
6664                setter(scope.$parent, remove(current, value, comparator));
6665            }
6666            if (checklistChange) {
6667                checklistChange(scope);
6668            }
6669        });
6670        function setChecked(newArr, oldArr) {
6671            scope.checked = contains(newArr, value, comparator);
6672        }
6673        if (angular.isFunction(scope.$parent.$watchCollection)) {
6674            scope.$parent.$watchCollection(attrs.checklistModel, setChecked);
6675        }
6676        else {
6677            scope.$parent.$watch(attrs.checklistModel, setChecked, true);
6678        }
6679    }
6680    return {
6681        restrict: 'A',
6682        priority: 1000,
6683        terminal: true,
6684        scope: true,
6685        compile: function (tElement, tAttrs) {
6686            if (tElement[0].tagName !== 'INPUT' || tAttrs.type !== 'checkbox') {
6687                throw 'checklist-model should be applied to `input[type="checkbox"]`.';
6688            }
6689            if (!tAttrs.checklistValue) {
6690                throw 'You should provide `checklist-value`.';
6691            }
6692            tElement.removeAttr('checklist-model');
6693            tElement.attr('ng-model', 'checked');
6694            return postLinkFn;
6695        },
6696    };
6697});
6698appDirectives.directive('numbersOnly', function ($log) {
6699    $log = $log.getInstance('directive :: numbers-only');
6700    return {
6701        require: 'ngModel',
6702        link: function (scope, element, attrs, ngModel) {
6703            if (!ngModel)
6704                return;
6705            var goodValue = 0;
6706            var lastEntryWasNumber = true;
6707            var step = _.isFinite(parseFloat(attrs['step']))
6708                ? parseFloat(attrs['step'])
6709                : attrs['step'];
6710            var min = _.isFinite(parseFloat(attrs['min']))
6711                ? parseFloat(attrs['min'])
6712                : attrs['min'];
6713            var max = _.isFinite(parseFloat(attrs['max']))
6714                ? parseFloat(attrs['max'])
6715                : attrs['max'];
6716            var required = attrs['required'];
6717            var validate = function (val) {
6718                var goodNumber = goodValue || 0;
6719                var thisNumber = parseFloat(val) || parseFloat(goodNumber) || 0;
6720                var isNumber = _.isFinite(thisNumber);
6721                if (isNumber) {
6722                    goodNumber = thisNumber;
6723                    if (step == 1)
6724                        goodNumber = Math.round(goodNumber);
6725                    if (!!min && goodNumber < min)
6726                        goodNumber = min;
6727                    if (!!max && goodNumber > max)
6728                        goodNumber = max;
6729                    if (min >= 0)
6730                        goodNumber = parseFloat(goodNumber.toString().replace(/-/g, ''));
6731                    goodNumber = parseFloat(goodNumber);
6732                }
6733                return goodNumber;
6734            };
6735            element.on('blur', function () {
6736                var val = $(this).val();
6737                goodValue = validate(val);
6738                return $(element).val(goodValue);
6739            });
6740            ngModel.$parsers.push(function (val) {
6741                var newValue = val || goodValue;
6742                goodValue = validate(newValue);
6743                $(element).val(goodValue);
6744                return goodValue;
6745            });
6746        },
6747    };
6748});
6749appDirectives.directive('inverted', function () {
6750    return {
6751        require: 'ngModel',
6752        link: function (scope, element, attrs, ngModel) {
6753            ngModel.$parsers.push(function (val) {
6754                return !val;
6755            });
6756            ngModel.$formatters.push(function (val) {
6757                return !val;
6758            });
6759        },
6760    };
6761});
6762appDirectives.directive('ngEnter', function () {
6763    return function (scope, elements, attrs) {
6764        elements.bind('keydown keypress', function (event) {
6765            if (event.which === 13) {
6766                scope.$apply(function () {
6767                    scope.$eval(attrs.ngEnter);
6768                });
6769                event.preventDefault();
6770            }
6771        });
6772    };
6773});
6774appDirectives.directive('schoolSideHeaderHeight', function ($timeout) {
6775    return {
6776        restrict: 'A',
6777        link: function (scope, element, attrs) {
6778            $timeout(function () {
6779                var asideHeaderHeight = angular
6780                    .element('aside.schoolpool-sidebar .header')
6781                    .outerHeight();
6782                var heightForOffest = asideHeaderHeight + 'px';
6783                var resultsContainer = angular.element('.results');
6784                resultsContainer.attr('style', 'margin-top:' + heightForOffest + ' !important');
6785            }, 1);
6786        },
6787    };
6788});
6789appDirectives.directive('addWidth', function () {
6790    return {
6791        scope: {
6792            container: '=',
6793            addWidth: '=',
6794        },
6795        restrict: 'A',
6796        link: function ($scope, $element, $attr) {
6797            var target = $($element).closest('.' + $scope.container);
6798            target.width(target.width() + $scope.addWidth);
6799        },
6800    };
6801});
6802appDirectives.directive('selectOn', function ($window) {
6803    return {
6804        restrict: 'A',
6805        link: function postLink(scope, element, attrs, ngModel) {
6806            var onEvent = attrs.selectOn || 'click';
6807            element.on(onEvent, function selectOnEvent() {
6808                var range;
6809                var node = this;
6810                var inputTYPES = ['INPUT', 'TEXTAREA'];
6811                var thisTYPE = element.prop('tagName').toUpperCase();
6812                var isInput = inputTYPES.indexOf(thisTYPE) > -1;
6813                if (isInput) {
6814                    if (!$window.getSelection().toString()) {
6815                        node.setSelectionRange(0, node.value.length);
6816                    }
6817                }
6818                else {
6819                    if (document.selection) {
6820                        range = document.body.createTextRange();
6821                        range.moveToElementText(node);
6822                        range.select();
6823                    }
6824                    else if (window.getSelection) {
6825                        range = document.createRange();
6826                        range.selectNodeContents(node);
6827                        window.getSelection().removeAllRanges();
6828                        window.getSelection().addRange(range);
6829                    }
6830                }
6831            });
6832        },
6833    };
6834});
6835appDirectives.directive('onEvent', function ($log, $timeout, $interval, $rootScope) {
6836    $log = $log.getInstance('onEvent');
6837    return {
6838        restrict: 'A',
6839        link: function postLink(scope, elem, attr) {
6840            var theFirstEvent = attr.onEvent || attr.onEventTrigger;
6841            var theEventToTrigger = attr.onEventTrigger || attr.onEvent;
6842            if (theFirstEvent && theEventToTrigger) {
6843                var pauseAttrEval = scope.$eval(attr.onEventPauseForDialogs);
6844                var obeyDialogs = 'onEventPauseForDialogs' in attr &&
6845                    angular.isUndefined(pauseAttrEval)
6846                    ? true
6847                    : !!pauseAttrEval;
6848                function stopChecking() {
6849                    if (scope.activeCheck) {
6850                        $interval.cancel(scope.activeCheck);
6851                        delete scope.activeCheck;
6852                    }
6853                }
6854                function continueEvent() {
6855                    stopChecking();
6856                    $timeout(function () {
6857                        var targetElement = angular.element(attr.onEventTarget);
6858                        if (targetElement.length)
6859                            targetElement.trigger(attr.onEventTrigger);
6860                    }, 10);
6861                }
6862                function checkForDialogs() {
6863                    if (obeyDialogs &&
6864                        ($rootScope.isDialogOpen ||
6865                            (vex && vex.getAllVexes().length) ||
6866                            angular.element('.vex-content').length)) {
6867                    }
6868                    else {
6869                        continueEvent();
6870                    }
6871                }
6872                elem.on(theFirstEvent, function () {
6873                    if (scope.activeCheck)
6874                        return false;
6875                    scope.activeCheck = $interval(checkForDialogs, 250, 1000);
6876                });
6877                scope.$on('$destroy', function () {
6878                    elem.off(attr.onEvent);
6879                    stopChecking();
6880                });
6881            }
6882        },
6883    };
6884});
6885appDirectives.directive('requireClickConfirmation', function ($log, $parse, Dialogs) {
6886    $log = $log.getInstance('requireClickConfirmation');
6887    return {
6888        restrict: 'A',
6889        priority: 0,
6890        link: function postLink(scope, element, attrs) {
6891            var proceed;
6892            var ngClick = $parse(attrs.ngClick);
6893            var defaultMessage = 'Are certain you wish to continue?';
6894            var confirmationMessage = attrs.requireConfirmation || defaultMessage;
6895            element.on('click', function (e) {
6896                if (!proceed) {
6897                    e.stopImmediatePropagation();
6898                    Dialogs.confirm({
6899                        message: confirmationMessage,
6900                        callback: function (confirmed) {
6901                            proceed = confirmed;
6902                            if (confirmed)
6903                                element.trigger('click');
6904                        },
6905                    });
6906                }
6907            });
6908            scope.$on('$destroy', function () {
6909                element.off('click');
6910            });
6911        },
6912    };
6913});
6914appDirectives.directive('requireConfirmation', function ($log, $compile) {
6915    $log = $log.getInstance('requireConfirmation');
6916    return {
6917        restrict: 'A',
6918        priority: 1001,
6919        terminal: true,
6920        compile: function (elem, attrs) {
6921            var origClick = attrs.confirmClick || attrs.ngClick;
6922            if (!angular.isDefined(attrs.confirmClick)) {
6923                attrs.ngClick = null;
6924                elem.removeAttr('ng-click');
6925            }
6926            elem.attr('confirm-click', origClick);
6927            var origMessage = attrs.requireConfirmation || attrs.confirmClickMessage || '';
6928            attrs.requireConfirmation = null;
6929            elem.removeAttr('require-confirmation');
6930            elem.attr('confirm-click-message', origMessage || '');
6931            return {
6932                pre: function (scope, iElem, iAttrs) { },
6933                post: function (scope, iElem, iAttrs) {
6934                    return $compile(iElem)(scope);
6935                },
6936            };
6937        },
6938    };
6939});
6940appDirectives.directive('confirmClick', function ($log, Dialogs, $sanitize) {
6941    $log = $log.getInstance('confirmClick');
6942    return {
6943        restrict: 'A',
6944        link: function (scope, elem, attrs) {
6945            var confirmClick = attrs.confirmClick;
6946            var defaultMessage = 'Are certain you wish to continue?';
6947            var customMessage = attrs.confirmClickMessage ||
6948                attrs.requireConfirmation ||
6949                defaultMessage;
6950            elem.on('click', function (e) {
6951                Dialogs.confirm({
6952                    unsafeMessage: $sanitize(customMessage),
6953                    callback: function (confirmed) {
6954                        if (confirmed)
6955                            scope.$apply(confirmClick);
6956                    },
6957                });
6958            });
6959            scope.$on('$destroy', function () {
6960                elem.off('click');
6961            });
6962        },
6963    };
6964});
6965appDirectives.directive('raPluralize', function ($log, $locale, $interpolate) {
6966    $log = $log.getInstance ? $log.getInstance('raPluralize') : $log;
6967    var BRACE = /\{\}/g, IS_WHEN = /^when(Minus)?(.+)$/;
6968    return {
6969        link: function (scope, element, attr) {
6970            var numberExp = attr.count, whenExp = attr.$attr.when && element.attr(attr.$attr.when), offset = attr.offset || 0, whens = scope.$eval(whenExp) || {}, whensExpFns = {}, startSymbol = $interpolate.startSymbol(), endSymbol = $interpolate.endSymbol(), braceReplacement = startSymbol + numberExp + '-' + offset + endSymbol, watchRemover = angular.noop, lastCount;
6971            var singularStr = element.text() || '';
6972            var pluralWhen = attr.pluralWhen;
6973            if (singularStr && pluralWhen) {
6974                scope.$watch(pluralWhen, function pluralWhenWatchAction(newVal) {
6975                    var appendStr = attr.append || 's';
6976                    var newText = singularStr + (newVal ? appendStr : '');
6977                    return updateElementText(newText);
6978                });
6979            }
6980            else {
6981                angular.forEach(attr, function (expression, attributeName) {
6982                    var tmpMatch = IS_WHEN.exec(attributeName);
6983                    if (tmpMatch) {
6984                        var whenKey = (tmpMatch[1] ? '-' : '') + lowercase(tmpMatch[2]);
6985                        whens[whenKey] = element.attr(attr.$attr[attributeName]);
6986                    }
6987                });
6988                angular.forEach(whens, function (expression, key) {
6989                    whensExpFns[key] = $interpolate(expression.replace(BRACE, braceReplacement));
6990                });
6991                scope.$watch(numberExp, function ngPluralizeWatchAction(newVal) {
6992                    var count = parseFloat(newVal);
6993                    var countIsNaN = isNaN(count);
6994                    if (!countIsNaN && !(count in whens)) {
6995                        count = $locale.pluralCat(count - offset);
6996                    }
6997                    if (count !== lastCount &&
6998                        !(countIsNaN && angular.isNumber(lastCount) && isNaN(lastCount))) {
6999                        watchRemover();
7000                        var whenExpFn = whensExpFns[count];
7001                        if (angular.isUndefined(whenExpFn)) {
7002                            if (newVal != null) {
7003                                $log.debug("ngPluralize: no rule defined for '" +
7004                                    count +
7005                                    "' in " +
7006                                    whenExp);
7007                            }
7008                            watchRemover = angular.noop;
7009                            updateElementText();
7010                        }
7011                        else {
7012                            watchRemover = scope.$watch(whenExpFn, updateElementText);
7013                        }
7014                        lastCount = count;
7015                    }
7016                });
7017            }
7018            function updateElementText(newText) {
7019                element.text(newText || '');
7020            }
7021        },
7022    };
7023});
7024appDirectives.factory('KendoThemeService', function (CONFIG, $q, $timeout, _) {
7025    var defaultTheme = CONFIG.kendoTheme || 'material';
7026    var currentTheme = getActiveTheme();
7027    var pendingChange = null;
7028    var service = {
7029        changeTheme: changeTheme,
7030        resetTheme: resetTheme,
7031        getActiveTheme: getActiveTheme,
7032    };
7033    return service;
7034    function changeTheme(newTheme) {
7035        if (!pendingChange && newTheme === currentTheme)
7036            return done();
7037        var doc = document;
7038        var kendoLinks = $("link[href*='kendo.']");
7039        var commonLink = kendoLinks.filter("[href*='kendo.common']");
7040        var skinLink = kendoLinks.filter(":not([href*='kendo.common'])");
7041        var skinExtension = skinLink.attr('rel') === 'stylesheet' ? '.css' : '.less';
7042        var skinRegex = /kendo\.\w+(\.min)?\.css/i;
7043        var newSkinUrl = skinLink
7044            .attr('href')
7045            .replace(skinRegex, 'kendo.' + newTheme + '$1' + skinExtension);
7046        var commonExtension = commonLink.attr('rel') === 'stylesheet' ? '.css' : '.less';
7047        function preloadStylesheets() {
7048            var files = [newSkinUrl];
7049            var promises = [];
7050            var elements = files.map(function (file) {
7051                var element = $("<img src='" + file + "' \/>");
7052                element.appendTo('head');
7053                var d = $q.defer();
7054                element[0].onerror = function (e) {
7055                    d.resolve();
7056                };
7057                promises.push(d.promise);
7058            });
7059            pendingChange = $q.all(promises);
7060            return pendingChange;
7061        }
7062        function replaceTheme() {
7063            var browser = kendo.support.browser;
7064            var oldSkinName = $(doc).data('kendoSkin');
7065            var newLink;
7066            if (browser.msie && browser.version < 10) {
7067                newLink = doc.createStyleSheet(newSkinUrl);
7068                $(doc.documentElement)
7069                    .removeClass('k-' + oldSkinName)
7070                    .addClass('k-' + newTheme);
7071                skinLink.remove();
7072            }
7073            else {
7074                newLink = skinLink.eq(0).clone().attr('href', newSkinUrl);
7075                newLink.insertBefore(skinLink[0]);
7076                skinLink.remove();
7077                $(doc.documentElement)
7078                    .removeClass('k-' + oldSkinName)
7079                    .addClass('k-' + newTheme);
7080            }
7081            return $timeout(function () { });
7082        }
7083        function done() {
7084            currentTheme = newTheme;
7085            pendingChange = null;
7086            return $q.when(true);
7087        }
7088        if (pendingChange) {
7089            return pendingChange
7090                .then(preloadStylesheets)
7091                .then(replaceTheme)
7092                .then(done);
7093        }
7094        else {
7095            return preloadStylesheets().then(replaceTheme).then(done);
7096        }
7097    }
7098    function resetTheme() {
7099        service.changeTheme(defaultTheme);
7100    }
7101    function getActiveTheme() {
7102        var doc = document;
7103        var kendoLinks = $("link[href*='kendo.']");
7104        var skinLink = kendoLinks.filter(":not([href*='kendo.common'])");
7105        var skinRegex = /.*kendo\.(\w+)(\.min)?\.css.*/i;
7106        var activeTheme = skinLink.attr('href').replace(skinRegex, '$1');
7107        return activeTheme;
7108    }
7109});
7110appDirectives.directive('kendoTheme', function (KendoThemeService, $timeout) {
7111    var directive = {
7112        restrict: 'EA',
7113        link: link,
7114    };
7115    return directive;
7116    function link($scope, $element, $attrs) {
7117        $attrs.$observe('kendoTheme', function (value) {
7118            $timeout(function () {
7119                KendoThemeService.changeTheme(value);
7120            }, 1);
7121        });
7122    }
7123});
7124appDirectives.directive('fillHeight', function ($window, $document, $debounce, $timeout) {
7125    return {
7126        restrict: 'A',
7127        link: function (scope, element, attrs) {
7128            var additionalPadding = attrs.additionalPadding;
7129            var footerSelector = attrs.footerSelector;
7130            var debounceWait = attrs.debounceWait;
7131            if (debounceWait === 0) {
7132                angular.element($window).on('resize', onWindowResize);
7133            }
7134            else {
7135                angular
7136                    .element($window)
7137                    .on('resize', $debounce(onWindowResize, debounceWait || 250));
7138                $timeout(onWindowResize, debounceWait || 250);
7139            }
7140            onWindowResize();
7141            function onWindowResize() {
7142                var footerElement = $(footerSelector);
7143                var footerElementHeight;
7144                if (footerElement.length === 1) {
7145                    footerElementHeight = footerElement.outerHeight(true);
7146                }
7147                else if (footerElement.length > 1) {
7148                    _.reduce(footerElement, function (f, v) {
7149                        v = v || 0;
7150                        return v + $(f).outerHeight(true);
7151                    });
7152                }
7153                else {
7154                    footerElementHeight = 0;
7155                }
7156                var elementOffsetTop = $(element).offset().top;
7157                additionalPadding = parseInt(additionalPadding) || 0;
7158                var elementHeight = $window.innerHeight -
7159                    elementOffsetTop -
7160                    footerElementHeight -
7161                    additionalPadding;
7162                element.css('height', elementHeight + 'px');
7163            }
7164        },
7165    };
7166});
7167appDirectives.directive('accountStatsWidget', function () {
7168    var directive = {
7169        restirct: 'EA',
7170        templateUrl: 'templates/widgets/account-stats-widget.html',
7171        scope: {
7172            userId: '=',
7173            showStatsButton: '=',
7174        },
7175        link: link,
7176    };
7177    return directive;
7178    function link($scope, $element, $attrs, $ctrl) { }
7179});
7180appDirectives.directive('tripplanButtonWrapperHeight', function ($log, $debounce) {
7181    return {
7182        restrict: 'A',
7183        link: function ($scope, $element, $attrs, $controllers) {
7184            $scope.height = $element.css('height');
7185            var updateHeight = $debounce(function () {
7186                $log.warn('TP BUTTON HEIGHT ... changed');
7187                var height = $element.css('height');
7188                var targetElement = $($attrs.heightTarget);
7189                targetElement.css('top', height);
7190                targetElement.css('height', 'calc(100% - ' + height + ')');
7191            }, 333);
7192            if ($attrs.heightWatchers) {
7193                $attrs.heightWatchers.split(',').forEach(function (val) {
7194                    $scope.$watch(val, updateHeight, false);
7195                });
7196            }
7197        },
7198    };
7199});
7200appDirectives.directive('replaceContent', function ($timeout) {
7201    var directive = {
7202        restrict: 'A',
7203        scope: {
7204            replaceContent: '@',
7205        },
7206        link: link,
7207    };
7208    return directive;
7209    function link($scope, $element, $attr, $ctrl) {
7210        var content = $element.html();
7211        $($element).empty();
7212        $timeout(function () {
7213            console.error('REPLACING CONTENT IN ', $($scope.replaceContent));
7214            $($scope.replaceContent).html(content);
7215        }, 500);
7216    }
7217});
7218appDirectives.directive('prependContent', function ($timeout) {
7219    var directive = {
7220        restrict: 'A',
7221        scope: {
7222            prependContent: '@',
7223        },
7224        link: link,
7225    };
7226    return directive;
7227    function link($scope, $element, $attr, $ctrl) {
7228        var content = $element.html();
7229        $($element).empty();
7230        $timeout(function () {
7231            console.error('REPLACING CONTENT IN ', $($scope.prependContent));
7232            $($scope.prependContent).prepend(content);
7233        }, 500);
7234    }
7235});
7236appDirectives.directive('appendContent', function ($timeout) {
7237    var directive = {
7238        restrict: 'A',
7239        scope: {
7240            appendContent: '@',
7241        },
7242        link: link,
7243    };
7244    return directive;
7245    function link($scope, $element, $attr, $ctrl) {
7246        var content = $element.html();
7247        $($element).empty();
7248        $timeout(function () {
7249            console.error('REPLACING CONTENT IN ', $($scope.appendContent));
7250            $($scope.appendContent).append(content);
7251        }, 500);
7252    }
7253});
7254appDirectives.directive('afterContent', function ($timeout) {
7255    var directive = {
7256        restrict: 'A',
7257        scope: {
7258            afterContent: '@',
7259        },
7260        link: link,
7261    };
7262    return directive;
7263    function link($scope, $element, $attr, $ctrl) {
7264        var content = $element.html();
7265        $($element).empty();
7266        $timeout(function () {
7267            console.error('REPLACING CONTENT IN ', $($scope.afterContent));
7268            $($scope.afterContent).after(content);
7269        }, 1000);
7270    }
7271});
7272appDirectives.directive('markdownElement', function (MarkdownEditor, MarkdownValidatorBridge) {
7273    return {
7274        scope: {
7275            fieldToken: '=',
7276        },
7277        require: 'ngModel',
7278        link: function ($scope, $element, $attrs, $ngModelCtrl) {
7279            var isValid = true;
7280            var previewIcon = null;
7281            var activeClass = 'fa fa-eye no-disable active';
7282            var previewSelector = 'a.fa.fa-eye.no-disable';
7283            var _bindContent = _.debounce(bindContent, 300);
7284            var userExtraTokens;
7285            (function init() {
7286                userExtraTokens = _.map(CONFIG.emailUserExtraTokens, function (field) { return "%%userExtras.".concat(field, "%%"); });
7287                $ngModelCtrl.$render = function () {
7288                    var value = $ngModelCtrl.$viewValue;
7289                    $scope.markdownInstance.value(value);
7290                    if (value)
7291                        $scope.validateTokens();
7292                };
7293                attachToDom();
7294                onDestroyCleanUp();
7295                $scope.watchField = doWatch();
7296                MarkdownValidatorBridge.attach($scope);
7297            })();
7298            $scope.validateTokens = validateTokens;
7299            function doWatch() {
7300                return $scope.$watch('fieldToken', function (newValue, oldValue) {
7301                    if (!newValue && !oldValue)
7302                        return;
7303                    if (newValue && newValue.name !== '%%token%%') {
7304                        var tokenObject = angular.copy(newValue);
7305                        if (tokenObject.customLink) {
7306                            insertCustomLink(tokenObject);
7307                        }
7308                        else {
7309                            insertFieldToken(tokenObject);
7310                        }
7311                    }
7312                });
7313            }
7314            function attachToDom() {
7315                $scope.markdownInstance = new MarkdownEditor($element[0]);
7316                $scope.markdownInstance.codemirror.on('change', _bindContent);
7317                bindTextEntryEvents();
7318            }
7319            function bindContent() {
7320                var value = $scope.markdownInstance.value();
7321                $ngModelCtrl.$setViewValue(value);
7322                setModelValidity(value.length);
7323            }
7324            function setModelValidity(hasContent) {
7325                $ngModelCtrl.$setValidity('required', hasContent);
7326            }
7327            function insertCustomLink(token) {
7328                var link = token.name.split('[]')[1];
7329                var currentPos = $scope.markdownInstance.codemirror.doc.getCursor();
7330                freezeEditor();
7331                insertToken(currentPos, token);
7332                highlightInsert({ line: currentPos.line, ch: currentPos.ch + 2 }, { name: link });
7333                unfreezeEditor();
7334                $scope.markdownInstance.codemirror.focus();
7335                $scope.markdownInstance.codemirror.doc.setCursor(currentPos.line, currentPos.ch + 1);
7336            }
7337            function insertFieldToken(token) {
7338                freezeEditor();
7339                doInsertAt($scope.markdownInstance.codemirror.doc.getCursor(), token);
7340                unfreezeEditor();
7341            }
7342            function doInsertAt(currentPos, token) {
7343                insertToken(currentPos, token);
7344                placeCursorAfterInsert(currentPos, token);
7345                highlightInsert(currentPos, token);
7346            }
7347            function bindTextEntryEvents() {
7348                $scope.markdownInstance.codemirror.setOption('extraKeys', {
7349                    Enter: function (cm) {
7350                        var lineBreak = '  \n';
7351                        cm.replaceSelection(lineBreak);
7352                    },
7353                });
7354                previewIcon = previewIcon || $(previewSelector);
7355                $scope.markdownInstance.codemirror.on('keyHandled', doSwap);
7356                previewIcon.click(doSwap);
7357            }
7358            function doSwap(event, shortCut) {
7359                if ((shortCut && shortCut === 'Cmd-P') ||
7360                    (event.type === 'click' &&
7361                        event.currentTarget.className === activeClass)) {
7362                    replaceTokens();
7363                }
7364            }
7365            function replaceTokens() {
7366                var preview = $('.editor-preview');
7367                preview.html(preview
7368                    .html()
7369                    .replace(/%%user.firstName%%|%%user.lastName%%|%%user.email%%|%%user.employeeID%%|%%user._id%%/g, function (token) {
7370                    var key = token.replace(/%%|user./g, '');
7371                    return $scope.$root.session.user[key];
7372                }));
7373                if (_.includes(userExtraTokens, '%%userExtras.vehicleSummaryImage%%')) {
7374                    preview.html(preview
7375                        .html()
7376                        .replace(/%%userExtras.vehicleSummaryImage%%/g, function () {
7377                        return "<a href=\"".concat(location.origin, "/#/vehicles/users/").concat($scope.$root.session.user._id, "/summary\" target=\"_blank\"><img style=\"width: 100%;\" src=\"./img/examples/vehicle-summary.png\" alt=\"vehicle summary\"></a>");
7378                    }));
7379                }
7380            }
7381            function freezeEditor() {
7382                $scope.markdownInstance.codemirror.setOption('readOnly', true);
7383            }
7384            function unfreezeEditor() {
7385                $scope.markdownInstance.codemirror.setOption('readOnly', false);
7386            }
7387            function insertToken(currentPos, token) {
7388                var currentLine = $scope.markdownInstance.codemirror.doc.getLine(currentPos.line);
7389                var currentRange = $scope.markdownInstance.codemirror.doc.getRange(currentPos, { line: currentPos.line, ch: currentLine.length });
7390                $scope.markdownInstance.codemirror.doc.replaceRange(token.name + currentRange, currentPos, { line: currentPos.line, ch: currentLine.length });
7391            }
7392            function placeCursorAfterInsert(currentPos, token) {
7393                $scope.markdownInstance.codemirror.focus();
7394                $scope.markdownInstance.codemirror.doc.setCursor(currentPos.line, currentPos.ch + token.name.length);
7395            }
7396            function validateTokens() {
7397                isValid = true;
7398                var lineCount = document.getElementsByClassName('CodeMirror-line').length;
7399                for (var currentLine = 0; currentLine < lineCount; currentLine++) {
7400                    var text = $scope.markdownInstance.codemirror.doc.getLine(currentLine);
7401                    if (text && text.indexOf('%%') !== -1) {
7402                        checkTokens(text, currentLine);
7403                    }
7404                }
7405                return isValid;
7406            }
7407            function checkTokens(text, line) {
7408                if (!text) {
7409                    return;
7410                }
7411                var validUserTokens = [];
7412                if (CONFIG.emailUserTokens && CONFIG.emailUserTokens.length) {
7413                    validUserTokens = CONFIG.emailUserTokens.map(function (token) {
7414                        return '%%user.' + token + '%%';
7415                    });
7416                }
7417                var validTokens = __spreadArray(__spreadArray([], validUserTokens, true), userExtraTokens, true);
7418                var re = /%%[\w\.]+%%/g;
7419                var token;
7420                while ((token = re.exec(text))) {
7421                    token.name = token[0];
7422                    if (validTokens.indexOf(token.name) !== -1) {
7423                        highlightInsert({ line: line, ch: token.index }, token);
7424                    }
7425                    else {
7426                        isValid = false;
7427                        highlightInvalid({ line: line, ch: token.index }, token);
7428                    }
7429                }
7430            }
7431            function highlightInvalid(startPosition, token) {
7432                $scope.markdownInstance.codemirror.doc.markText(startPosition, {
7433                    line: startPosition.line,
7434                    ch: startPosition.ch + token.name.length,
7435                }, { className: 'markdown-highlight-warning', priority: 1 });
7436            }
7437            function highlightInsert(currentPos, token) {
7438                $scope.markdownInstance.codemirror.doc.markText(currentPos, { line: currentPos.line, ch: currentPos.ch + token.name.length }, {
7439                    className: 'markdown-highlight-positive',
7440                    atomic: true,
7441                    priority: 1,
7442                });
7443            }
7444            function onDestroyCleanUp() {
7445                $element.on('$destroy', function () {
7446                    if (previewIcon) {
7447                        previewIcon.off('click', doSwap);
7448                        previewIcon = null;
7449                    }
7450                    if ($scope.markdownInstance) {
7451                        $scope.markdownInstance.codemirror.off('keyHandled', doSwap);
7452                        $scope.markdownInstance.codemirror.off('change', _bindContent);
7453                        $scope.markdownInstance.toTextArea();
7454                        $scope.markdownInstance = null;
7455                    }
7456                    if ($scope.watchField) {
7457                        $scope.watchField();
7458                    }
7459                });
7460            }
7461        },
7462    };
7463});
7464appDirectives.service('MarkdownEditor', function (Dialogs) {
7465    var toolbarInfo = {
7466        name: 'image info',
7467        action: 'https://imageresize.org/',
7468        title: 'Please make sure images have a width less than 400px to accommodate for mobile viewing. You can use this helpful tool to resize your images.',
7469        className: 'fas fa-info-circle',
7470        id: 'info-button',
7471    };
7472    return function (selector, options) {
7473        var defaultOptions = {
7474            element: _.isElement(selector)
7475                ? selector
7476                : document.getElementById(selector),
7477            toolbar: [
7478                'bold',
7479                'italic',
7480                'strikethrough',
7481                '|',
7482                'heading-1',
7483                'heading-2',
7484                'heading-3',
7485                '|',
7486                'quote',
7487                'unordered-list',
7488                'ordered-list',
7489                '|',
7490                'link',
7491                'table',
7492                '|',
7493                'preview',
7494                'clean-block',
7495                'guide',
7496                toolbarInfo,
7497            ],
7498            autosave: false,
7499        };
7500        return new SimpleMDE(_.merge(defaultOptions, options || {}));
7501    };
7502});
7503appDirectives.component('customProfileField', {
7504    bindings: {
7505        field: '<',
7506        user: '<',
7507    },
7508    template: '<div ng-include="$ctrl.field.template" ng-init="$ctrl=$ctrl"></div>',
7509    controller: function (CONFIG) {
7510        this.CONFIG = CONFIG;
7511    },
7512});
7513var EMPLOYER_NAME_CPF_TEMPLATE = '/templates/account/profile-fields/employer-name-custom.html';
7514function employerNameUsesCustomProfileField(config) {
7515    var fields = config && config.customProfileFields;
7516    if (!Array.isArray(fields)) {
7517        return false;
7518    }
7519    return fields.some(function (field) {
7520        return field && field.template === EMPLOYER_NAME_CPF_TEMPLATE;
7521    });
7522}
7523appDirectives.filter('employerNameUsesCustomProfileField', function () {
7524    return function (config) {
7525        return employerNameUsesCustomProfileField(config);
7526    };
7527});
7528appDirectives.component('commutehubHistoryLauncher', {
7529    template: "\n    <div class=\"text center\">\n    <button class=\"btn btn-large btn-default btn-block mt-10\"\n      ng-click=\"$ctrl.showModal()\">Trip History</button>\n      <div\n        modal-scope name=\"commutehubHistoryAppModal\" v-modal=\"/templates/premium/commutehub-app-modal.html\">\n      </div>\n    </div>\n  ",
7530    controller: function ($scope) {
7531        $scope.iframeConfig = {
7532            appBaseUrl: '/hub/trip-logs/history',
7533            shellName: 'commutehubHistoryAppModal',
7534            origin: window.location.origin,
7535        };
7536        CommuteHubAppIframeController.call(this, $scope);
7537    },
7538});
7539appDirectives.component('commutehubTriplogLauncher', {
7540    template: "\n    <div class=\"text center\">\n    <button class=\"btn btn-large btn-default btn-block mt-10\"\n      ng-click=\"$ctrl.showModal()\">Public Transit / Carpool</button>\n      <div modal-scope name=\"commutehubTriplogAppModal\" v-modal=\"/templates/premium/commutehub-app-modal.html\"></div>\n    </div>\n  ",
7541    controller: function ($scope) {
7542        $scope.iframeConfig = {
7543            appBaseUrl: '/hub/trip-logs/create',
7544            shellName: 'commutehubTriplogAppModal',
7545            origin: window.location.origin,
7546        };
7547        CommuteHubAppIframeController.call(this, $scope);
7548    },
7549});
7550appDirectives.component('commutehubPerksLauncher', {
7551    bindings: {
7552        btnText: '=',
7553    },
7554    template: "\n    <div>\n      <br>\n      <button ng-click=\"$ctrl.showModal()\" class=\"btn btn-perk btn-lg\">{{ ::$ctrl.btnText }}</button>\n      <div modal-scope name=\"commutehubPerksAppModal\" v-modal=\"/templates/premium/commutehub-app-modal.html\"></div>\n    </div>\n  ",
7555    controller: function ($scope) {
7556        $scope.iframeConfig = {
7557            appBaseUrl: '/hub/commute-perks/',
7558            shellName: 'commutehubPerksAppModal',
7559            origin: window.location.origin,
7560            isLargeModal: true,
7561        };
7562        CommuteHubAppIframeController.call(this, $scope);
7563    },
7564});
7565appDirectives.controller('CommuteHubAppIframeController', CommuteHubAppIframeController);
7566function CommuteHubAppIframeController($scope) {
7567    var $ctrl = this;
7568    $ctrl.setConfig = function () {
7569        if (!$scope.iframeConfig) {
7570            throw new Error('Missing config for commuteHub launcher');
7571        }
7572        $ctrl.iframeConfig = $scope.iframeConfig;
7573    };
7574    $ctrl.$onInit = function () {
7575        try {
7576            $ctrl.setConfig();
7577            $ctrl.setRuntimeEnv();
7578        }
7579        catch (e) {
7580            console.error(e);
7581        }
7582    };
7583    $ctrl.setRuntimeEnv = function () {
7584        $ctrl.appUrl = $ctrl.iframeConfig.appUrl = $ctrl.buildUrl();
7585        Object.freeze($ctrl.iframeConfig);
7586        var width = $ctrl.iframeConfig.isLargeModal ? 700 : 500;
7587        $ctrl.modalContainerRestrictions = "width: ".concat(width, "px!important; min-width: ").concat(width, "px!important; max-width: ").concat(width, "px!important; max-height: 900px!important; height: 90vh!important;");
7588    };
7589    $ctrl.showModal = function () {
7590        $scope.showModal($ctrl.iframeConfig.shellName, $scope);
7591    };
7592    $ctrl.buildUrl = function () {
7593        return "".concat(window.location.origin).concat($ctrl.iframeConfig.appBaseUrl);
7594    };
7595}
7596;
7597'use strict';
7598angular
7599    .module('vtmoFront')
7600    .config(function ($stateProvider, $urlRouterProvider, $sceDelegateProvider, $urlMatcherFactoryProvider, vtmoResolvesProvider, sessionSecurityProvider) {
7601    $sceDelegateProvider.resourceUrlWhitelist(['self', '**']);
7602    $urlMatcherFactoryProvider.strictMode(false);
7603    $urlRouterProvider
7604        .when('/ie', function ($state) {
7605        setTimeout(function () {
7606            window.location.href = '/ie';
7607        }, 10);
7608    })
7609        .when('/fr', function ($state) {
7610        Localize.setLanguage('fr-CA');
7611        setTimeout(function () {
7612            window.location.href = '/';
7613        }, 10);
7614    })
7615        .otherwise('/');
7616    $stateProvider
7617        .state('home', {
7618        url: '/?token&migrate&confirmEmail',
7619        data: {
7620            iframeMap: false,
7621        },
7622        resolve: {
7623            defaultChallenge: function ($q, CONFIG, vChallenges, $log) {
7624                $log = $log.getInstance('State: home - defaultChallenge');
7625                var deferred = $q.defer();
7626                if (CONFIG.defaultChallengeId) {
7627                    $log.debug('getting defaultChallenge', CONFIG.defaultChallengeId);
7628                    vChallenges.get(CONFIG.defaultChallengeId).then(function onSuccess(defaultChallenge) {
7629                        $log.debug('defaultChallenge', CONFIG.defaultChallengeId, defaultChallenge);
7630                        deferred.resolve(defaultChallenge);
7631                    }, function onError(error) {
7632                        $log.error('ERROR : defaultChallenge not found', CONFIG.defaultChallengeId, error);
7633                        deferred.resolve();
7634                    });
7635                    return deferred.promise;
7636                }
7637                else {
7638                    return null;
7639                }
7640            },
7641        },
7642        views: {
7643            '': {
7644                templateUrl: CONFIG.homepageTemplate,
7645                controller: function ($scope, $rootScope, $state, $stateParams, $timeout, $http) {
7646                    $scope.stats = {};
7647                    $http
7648                        .get('/api/v1/triplogreports/system')
7649                        .then(function (stats) {
7650                        $scope.stats = stats.data;
7651                    });
7652                    if ($stateParams.migrate != null) {
7653                        $scope.globalModalShow('account.migrate-account', {
7654                            disableBackdropClick: true,
7655                        });
7656                    }
7657                    else if ($stateParams.token != null) {
7658                        $scope.globalModalShow('account.reset-password', {
7659                            disableBackdropClick: true,
7660                        });
7661                    }
7662                    else if ($stateParams.confirmEmail != null) {
7663                        $scope.globalModalShow('account.confirm-email', {
7664                            disableBackdropClick: true,
7665                        });
7666                    }
7667                    else if (!$rootScope.onMobileDevice) {
7668                        angular.element(document).ready(function () {
7669                        });
7670                    }
7671                    $rootScope.$watch('session.user', function (user, prevUser) {
7672                        if (!!user && !!!prevUser) {
7673                            if (!$rootScope.skipDashboardRedirect &&
7674                                $state.current.name !== 'dashboard.plan')
7675                                $state.go(CONFIG.defaultUserLandingState);
7676                        }
7677                    });
7678                },
7679            },
7680            'leaderboard@home': {
7681                templateUrl: '/templates/widgets/leaderboard-widget.html',
7682            },
7683            'user-leaderboard@home': {
7684                templateUrl: '/templates/widgets/user-leaderboard-widget.html',
7685                controller: function ($scope, vTriplogreports, defaultChallenge) {
7686                    $scope.refresh = function () {
7687                        if (defaultChallenge) {
7688                            $scope.$parent.defaultChallenge = $scope.defaultChallenge =
7689                                defaultChallenge;
7690                            defaultChallenge
7691                                .getList('users', { limit: 5 })
7692                                .then(function (users) {
7693                                $scope.$parent.challengeUsers = $scope.users = users;
7694                            });
7695                        }
7696                        else {
7697                            vTriplogreports
7698                                .one('system')
7699                                .getList('leaders', { limit: 5 })
7700                                .then(function (result) {
7701                                $scope.$parent.challengeUsers = $scope.users = result;
7702                            });
7703                        }
7704                    };
7705                    $scope.refresh();
7706                },
7707            },
7708            'network-leaderboard@home': {
7709                templateUrl: '/templates/widgets/network-leaderboard-widget.html',
7710                controller: function ($scope, vTriplogreports, defaultChallenge) {
7711                    $scope.refresh = function () {
7712                        if (defaultChallenge) {
7713                            $scope.$parent.defaultChallenge = $scope.defaultChallenge =
7714                                defaultChallenge;
7715                            defaultChallenge
7716                                .getList('networks', { limit: 5 })
7717                                .then(function (networks) {
7718                                $scope.$parent.challengeNetworks = $scope.networks =
7719                                    networks;
7720                            });
7721                        }
7722                        else {
7723                            vTriplogreports
7724                                .one('system')
7725                                .getList('networks', { limit: 5 })
7726                                .then(function (result) {
7727                                $scope.$parent.challengeNetworks = $scope.networks =
7728                                    result;
7729                            });
7730                        }
7731                    };
7732                    $scope.refresh();
7733                },
7734            },
7735        },
7736    })
7737        .state('badge', {
7738        url: '/badge/:badgeId/:userId',
7739        controller: function ($rootScope, $state, $stateParams, $timeout) {
7740            $rootScope.badgePidgeon = $stateParams;
7741            var extraScope = {};
7742            if ($stateParams.badgeId)
7743                extraScope.badgeId = $stateParams.badgeId;
7744            $timeout(function () {
7745                $rootScope.globalModalShow('badges.modal', extraScope);
7746            }, 500);
7747            $state.go('home');
7748        },
7749    })
7750        .state('account', {
7751        abstract: true,
7752        url: '/account',
7753        data: {
7754            iframeMap: true,
7755        },
7756        template: '<ui-view/>',
7757        controller: function () {
7758        },
7759        title: 'Account Edit',
7760        resolve: {
7761            userSession: sessionSecurityProvider.requireUser(),
7762        },
7763    })
7764        .state('account.register', {
7765        url: '/register',
7766        title: 'Register',
7767        template: '/templates/account/register.html',
7768    })
7769        .state('account.login', {
7770        url: '/login',
7771        title: 'Log In',
7772        templateUrl: '/templates/account/login.html',
7773        controller: 'AccountLoginController',
7774    })
7775        .state('account.edit', {
7776        url: '/edit',
7777        abstract: true,
7778        templateUrl: '/templates/account/edit.html',
7779        title: 'Account Edit',
7780        data: {
7781            iframeMap: false,
7782        },
7783        resolve: {
7784            user: function (vtmoResolves, $q, $location, vSession, vError) {
7785                return vtmoResolves.userSession($q, $location, vSession, vError);
7786            },
7787        },
7788    })
7789        .state('account.edit.personal', {
7790        url: '/',
7791        templateUrl: '/templates/account/edit-personal.html',
7792        title: 'Account Edit Personal Details',
7793        data: {
7794            menuTitle: 'Personal Details',
7795            weight: 0,
7796        },
7797        controller: 'AccountEditController',
7798    })
7799        .state('account.edit.stats', {
7800        url: '/stats',
7801        templateUrl: '/templates/account/edit-stats.html',
7802        title: 'Account Statistics',
7803        data: {
7804            menuTitle: 'My Statistics',
7805            weight: 0,
7806        },
7807        controller: 'AccountEditController',
7808    })
7809        .state('account.edit.public', {
7810        url: '/public',
7811        templateUrl: '/templates/account/edit-public.html',
7812        title: 'Account Edit Public Details',
7813        data: {
7814            menuTitle: 'Public Profile',
7815            weight: 0,
7816        },
7817        controller: 'AccountEditController',
7818    })
7819        .state('account.edit.networks', {
7820        url: '/networks',
7821        templateUrl: '/templates/account/edit-networks.html',
7822        data: {
7823            menuTitle: 'My Networks',
7824            weight: 0,
7825        },
7826        controller: 'AccountEditController',
7827    })
7828        .state('account.edit.password', {
7829        url: '/password',
7830        templateUrl: '/templates/account/edit-password.html',
7831        title: 'Account Edit Password',
7832        data: {
7833            menuTitle: 'Login Settings',
7834            weight: 0,
7835        },
7836        controller: 'AccountEditController',
7837    })
7838        .state('account.edit.delete', {
7839        url: '/delete',
7840        templateUrl: '/templates/account/edit-delete.html',
7841        title: 'Account Close',
7842        data: {
7843            menuTitle: CONFIG.accountDeactiveTitle,
7844            weight: 999,
7845        },
7846        controller: 'AccountEditController',
7847    })
7848        .state('account.edit.diagnostics', {
7849        url: '/diagnostics',
7850        templateUrl: '/templates/account/edit-diagnostics.html',
7851        data: {
7852            menuTitle: 'Support Diagnostics',
7853            weight: 999,
7854        },
7855        controller: 'AccountEditController',
7856    })
7857        .state('account.forgot-password', {
7858        url: '/forgot-password',
7859        templateUrl: '/templates/account/forgot-password.html',
7860        controller: function () {
7861        },
7862    })
7863        .state('account.reset-password', {
7864        url: '/reset-password',
7865        templateUrl: '/templates/account/reset-password.html',
7866        controller: function () {
7867        },
7868    })
7869        .state('account.change-password', {
7870        url: '/change-password',
7871        templateUrl: '/templates/account/change-password.html',
7872        controller: function () {
7873        },
7874    })
7875        .state('networks', {
7876        abstract: false,
7877        data: {
7878            iframeMap: true,
7879        },
7880        url: '/networks',
7881        template: '<ui-view class="col-md-10 col-md-offset-1 view-networks"> <ul> <li ng-repeat="net in publicNetworks"> <a ui-sref="networks.network({networkId:net._id})">{{net.name}}</a> </li> </ul> </ui-view>',
7882        controller: function ($scope, $state, vNetworks) {
7883            $scope.$watch('session.user', function (user) {
7884                vNetworks.getList().then(function (nets) {
7885                    $scope.publicNetworks = nets;
7886                });
7887            });
7888        },
7889    })
7890        .state('networks.network', {
7891        url: '/:networkId?join',
7892        templateUrl: '/templates/networks/network.html',
7893        controller: 'NetworkAssocProfileController',
7894    })
7895        .state('admin', {
7896        abstract: true,
7897        data: {
7898            showNav: true,
7899        },
7900        url: '/admin',
7901        templateUrl: '/templates/admin/new/_layout.html',
7902        resolve: {
7903            adminUser: function (vtmoResolves, $q, $location, vSession, vError) {
7904                return vtmoResolves.adminUserSession($q, $location, vSession, vError);
7905            },
7906        },
7907        controller: function (adminUser) { },
7908    })
7909        .state('admin.dashboard', {
7910        url: '/',
7911        views: {
7912            content: {
7913                templateUrl: '/templates/admin/dashboard.html',
7914                controller: 'AdminDashboardController',
7915            },
7916        },
7917    })
7918        .state('admin.users', {
7919        url: '/users',
7920        abstract: true,
7921        views: {
7922            content: {
7923                templateUrl: '/templates/admin/users.html',
7924            },
7925        },
7926    })
7927        .state('admin.users.list', {
7928        url: '',
7929        templateUrl: '/templates/admin/users.list.html',
7930        controller: 'AdminUserListController',
7931    })
7932        .state('admin.users.detail', {
7933        url: '/:userId?tab',
7934        resolve: {
7935            userId: function ($stateParams, $q) {
7936                var deferred = $q.defer();
7937                deferred.resolve($stateParams.userId);
7938                return deferred.promise;
7939            },
7940        },
7941        templateUrl: '/templates/admin/users.detail.html',
7942        controller: 'AdminUserDetailController',
7943    })
7944        .state('admin.networks', {
7945        url: '/networks',
7946        abstract: true,
7947        views: {
7948            content: {
7949                templateUrl: '/templates/admin/networks.html',
7950            },
7951        },
7952    })
7953        .state('admin.networks.list', {
7954        url: '',
7955        templateUrl: '/templates/admin/networks.list.html',
7956        controller: 'AdminNetworkListController',
7957    })
7958        .state('admin.networks.detail', {
7959        url: '/:networkId',
7960        resolve: {
7961            networkId: function ($stateParams, $q) {
7962                var deferred = $q.defer();
7963                deferred.resolve($stateParams.networkId);
7964                return deferred.promise;
7965            },
7966        },
7967        templateUrl: '/templates/admin/networks.detail.html',
7968        controller: 'AdminNetworkDetailController',
7969    })
7970        .state('admin.triplogs', {
7971        url: '/triplogs',
7972        views: {
7973            content: {
7974                templateUrl: '/templates/admin/triplogs.html',
7975            },
7976        },
7977    })
7978        .state('admin.tripplans', {
7979        url: '/tripplans',
7980        abstract: true,
7981        views: {
7982            content: {
7983                templateUrl: '/templates/admin/tripplans.layout.html',
7984            },
7985        },
7986    })
7987        .state('admin.tripplans.map', {
7988        url: '',
7989        templateUrl: '/templates/admin/tripplans.map.html',
7990        controller: function ($scope, vTripplans, vTripsearches, $timeout, $filter, $http, NgTableParams, $q) {
7991            $scope.mapData = [];
7992            function paramsToUrlParams(params) {
7993                var p = params;
7994                var newParams = {};
7995                newParams.page = p.page;
7996                newParams.count = p.count;
7997                newParams.query = {};
7998                newParams.sort = {};
7999                return newParams;
8000            }
8001            $scope.getNetworkNames = function (networks) {
8002                return _.map(networks, 'name');
8003            };
8004            $scope.paginationParams = {};
8005            $scope.tripTypes = function () {
8006                return [
8007                    { id: 'Commute', title: 'Commute' },
8008                    { id: 'Event', title: 'Event' },
8009                ];
8010            };
8011            $scope.tableParams = new NgTableParams({
8012                page: 1,
8013                count: 100,
8014                sorting: { created: 'desc' },
8015            }, {
8016                total: 0,
8017                counts: [100, 250, 500],
8018                getData: function (params) {
8019                    var urlParams = paramsToUrlParams(params._params);
8020                    return $http
8021                        .get('/api/v1/tripplans', {
8022                        params: urlParams,
8023                    })
8024                        .then(function (data) {
8025                        _.forEach(data.data.results, function (item) {
8026                            if (item.shared && item.shared.networks) {
8027                                item.sharedNetworkNames = $scope
8028                                    .getNetworkNames(item.shared.networks)
8029                                    .join(', ');
8030                            }
8031                            if (item.user && item.user.networks) {
8032                                item.userNetworkNames = $scope
8033                                    .getNetworkNames(item.user.networks)
8034                                    .join(', ');
8035                            }
8036                            if (item.relatedEvent) {
8037                                item.type = 'Event';
8038                            }
8039                            else {
8040                                item.type = 'Commute';
8041                            }
8042                            item.visible = true;
8043                        });
8044                        params.total(data.data.count);
8045                        var returnedData = data.data.results;
8046                        var filter = params.filter() || {};
8047                        var filteredData = $filter('oldFilter')(returnedData, filter);
8048                        var orderedData = params.sorting()
8049                            ? $filter('orderBy')(filteredData, params.orderBy())
8050                            : filteredData;
8051                        $scope.mapData = orderedData;
8052                        $scope.paginationParams = params._params;
8053                        return orderedData;
8054                    });
8055                },
8056            });
8057            $scope.reload = function () {
8058                $scope.tableParams.reload();
8059            };
8060        },
8061    })
8062        .state('admin.tripsearches', {
8063        url: '/tripsearches',
8064        views: {
8065            content: {
8066                templateUrl: '/templates/admin/tripsearches.layout.html',
8067            },
8068        },
8069    })
8070        .state('admin.tripsearches.map', {
8071        url: '/',
8072        templateUrl: '/templates/admin/tripsearches.map.html',
8073        controller: function ($scope) {
8074            alert('tripsearches');
8075        },
8076    })
8077        .state('admin.tools.vanpool', {
8078        url: '/vanpool',
8079        templateUrl: '/templates/admin/tools/vanpool/vanpool.html',
8080    })
8081        .state('dashboard', {
8082        url: '/dashboard',
8083        abstract: true,
8084        template: '<div ui-view></div>',
8085        title: 'Dashboard',
8086    })
8087        .state('dashboard.plan', {
8088        url: '/plan/:from/:to/:selectedModes?date&time&event&ref&extraContent&embedded&modes&initialMode&recommendedMode&siteId&otpParams?',
8089        data: {
8090            iframeMap: false,
8091            mobileMap: true,
8092        },
8093        title: 'Trip Planning',
8094        onEnter: function (CONFIG, esriContainer, $stateParams, SubsiteService, vSession) {
8095            if (CONFIG.tripplanMapProvider &&
8096                CONFIG.tripplanMapProvider === 'esri') {
8097                esriContainer.loadScripts();
8098            }
8099            if ($stateParams.siteId && !vSession.user) {
8100                var subsite = SubsiteService.getSubsiteById($stateParams.siteId);
8101                if (subsite && subsite.primaryNetwork) {
8102                    SubsiteService.setActiveSubsite(subsite);
8103                }
8104            }
8105            if ($('#esri-map').length) {
8106                $('#esri-map').remove();
8107            }
8108        },
8109        views: {
8110            '@': {
8111                templateUrl: '/templates/tripplan/results.html',
8112                controllerAs: 'resultsCtrl',
8113                controller: 'TripplanResultCtrl',
8114                resolve: {
8115                    activeSearch: function ($q, SubsiteService, $log, $stateParams, CONFIG, LocationService, vTripsearches, $rootScope) {
8116                        if ($stateParams.extraContent) {
8117                            $rootScope.extraContent = $stateParams.extraContent;
8118                        }
8119                        if ($stateParams.embedded) {
8120                            $rootScope.isEmbedded = true;
8121                        }
8122                        $log = $log.getInstance('Resolve(dashboard.plan.activeSearch)');
8123                        var deferred = $q.defer();
8124                        var params = $stateParams;
8125                        var activeSearch = {};
8126                        var onFromSuccess = function (from) {
8127                            activeSearch.from = from;
8128                            checkResolveComplete();
8129                        };
8130                        var onFromError = function () {
8131                            activeSearch.from = null;
8132                            checkResolveComplete();
8133                        };
8134                        if (params.otpParams) {
8135                            console.error('OTP Params Passed');
8136                            activeSearch.otpParams = params.otpParams;
8137                        }
8138                        LocationService.parseLocationString(params.from).then(onFromSuccess, onFromError);
8139                        var onToSuccess = function (to) {
8140                            activeSearch.to = to;
8141                            checkResolveComplete();
8142                        };
8143                        var onToError = function () {
8144                            activeSearch.to = null;
8145                            checkResolveComplete();
8146                        };
8147                        LocationService.parseLocationString(params.to).then(onToSuccess, onToError);
8148                        var date, time;
8149                        try {
8150                            if (params.date != null) {
8151                                date = moment(params.date, 'YYYY-MM-DD').format('YYYY-MM-DD');
8152                            }
8153                            else {
8154                                date = moment(new Date()).format('YYYY-MM-DD');
8155                            }
8156                            if (params.time != null) {
8157                                time = moment(params.time, 'hh:mm A').format('hh:mm A');
8158                            }
8159                            else {
8160                                time = moment(new Date()).format('hh:mm A');
8161                            }
8162                        }
8163                        catch (error) {
8164                            date = moment(new Date()).format('YYYY-MM-DD');
8165                            time = moment(new Date()).format('hh:mm A');
8166                        }
8167                        activeSearch.date = date;
8168                        activeSearch.time = time;
8169                        if (params.event) {
8170                            activeSearch.event = params.event;
8171                        }
8172                        if (params.initialMode) {
8173                            activeSearch.initialMode = params.initialMode;
8174                        }
8175                        if (params.recommendedMode &&
8176                            CONFIG.tripplanRecommendedMode.enabled) {
8177                            activeSearch.recommendedMode = JSON.parse(params.recommendedMode);
8178                        }
8179                        activeSearch.riderView = true;
8180                        activeSearch.driverView = false;
8181                        if (params.modes) {
8182                            var availableModes = CONFIG.tripplanModes;
8183                            try {
8184                                var modes = params.modes.split(',');
8185                                if (_.every(modes, function (desiredMode) {
8186                                    return _.includes(availableModes, desiredMode);
8187                                })) {
8188                                    activeSearch.modes = modes;
8189                                }
8190                            }
8191                            catch (e) {
8192                            }
8193                        }
8194                        function checkResolveComplete() {
8195                            $log.debug('checkResolveComplete');
8196                            if (activeSearch.from !== undefined &&
8197                                activeSearch.to !== undefined &&
8198                                activeSearch.date !== undefined &&
8199                                activeSearch.time !== undefined) {
8200                                $log.debug('checkResolveComplete', 'COMPLETE', activeSearch);
8201                                if (SubsiteService.areSubsitesEnabled()) {
8202                                    SubsiteService.lookupTripSearchSubsite(vTripsearches.fromObject(activeSearch)).then(function (subsite) {
8203                                        if (subsite &&
8204                                            subsite.tripplanModes &&
8205                                            !params.modes) {
8206                                            activeSearch.modes = subsite.tripplanModes;
8207                                        }
8208                                        deferred.resolve(vTripsearches.fromObject(activeSearch));
8209                                    }, function () {
8210                                        deferred.resolve(vTripsearches.fromObject(activeSearch));
8211                                    });
8212                                }
8213                                else {
8214                                    deferred.resolve(vTripsearches.fromObject(activeSearch));
8215                                }
8216                            }
8217                            else {
8218                                $log.debug('checkResolveComplete', 'INCOMPLETE', activeSearch);
8219                            }
8220                        }
8221                        return deferred.promise;
8222                    },
8223                },
8224            },
8225        },
8226    })
8227        .state('dashboard.dashboard', {
8228        url: '/:dash',
8229        data: {
8230            iframeMap: true,
8231        },
8232        title: 'Dashboard',
8233        params: {
8234            dash: {
8235                squash: true,
8236            },
8237        },
8238        views: {
8239            '': {
8240                resolve: {
8241                    user: function (vtmoResolves, $q, $location, vSession, vError) {
8242                        return vtmoResolves.userSession($q, $location, vSession, vError);
8243                    },
8244                },
8245                templateUrl: '/templates/dashboard/layout.html',
8246                controller: function ($scope, $state, $stateParams, CONFIG, user) {
8247                    if ($stateParams.dash &&
8248                        !CONFIG.dashboards.hasOwnProperty($stateParams.dash))
8249                        return $state.go('dashboard.dashboard', { dash: null }, { reload: true });
8250                    var userDashboard = user.userAppSettings && user.userAppSettings.unityDashboard
8251                        ? user.userAppSettings.unityDashboard
8252                        : CONFIG.defaultDashboard;
8253                    var currentDashboard = $stateParams.dash || userDashboard;
8254                    $scope.dashboard =
8255                        CONFIG.dashboards[currentDashboard] ||
8256                            CONFIG.dashboards.default;
8257                },
8258            },
8259            '[email protected]': {
8260                templateUrl: '/templates/widgets/triplog-widget.html',
8261            },
8262            '[email protected]': {
8263                template: '<smart-triplog-widget></smart-triplog-widget>',
8264            },
8265            '[email protected]': {
8266                templateUrl: '/templates/widgets/profile-widget.html',
8267                resolve: {
8268                    userData: function () {
8269                        return null;
8270                    },
8271                },
8272                controller: function ($scope, $rootScope, userData, SessionUserDataService, $state, $log) {
8273                    'use strict';
8274                    $log = $log.getInstance('[email protected]');
8275                    $scope.user = userData || $scope.session.user;
8276                    $scope.sessionData = SessionUserDataService;
8277                    $scope.$watch('session.user', function (user) {
8278                        $scope.user = user;
8279                        if (user)
8280                            session.user.getList('networks').then(function (nets) {
8281                                $scope.networks = nets;
8282                            });
8283                        if (user)
8284                            session.user
8285                                .getList('managednetworks')
8286                                .then(function (nets) {
8287                                $scope.managedNetworks = nets;
8288                            });
8289                    });
8290                    $scope.$watch('facebook.facebookUser', function (user) {
8291                        if (user) {
8292                            $scope.user.facebookPhotoUrl =
8293                                'http://graph.facebook.com/' + user.id + '/picture';
8294                            $scope.user.firstName = user.first_name;
8295                            $scope.user.lastName = user.last_name;
8296                            $scope.user.email = user.email;
8297                            $scope.user.facebookAccessToken =
8298                                $scope.facebook.facebookAccessToken;
8299                            $scope.user.password = undefined;
8300                        }
8301                        else {
8302                            if ($scope.user)
8303                                $scope.user.facebookAccessToken = undefined;
8304                        }
8305                    });
8306                    $scope.$watch('sessionData.badges', function (newVal, oldVal) {
8307                        if (angular.isArray(newVal) &&
8308                            angular.isArray(oldVal) &&
8309                            newVal.length > oldVal.length) {
8310                            _.forEach(newVal, function (badge) {
8311                                if (angular.isObject(badge)) {
8312                                    if (!_.some(oldVal, { _id: badge._id })) {
8313                                        $rootScope.globalModalShow('badges.modal', {
8314                                            badgeId: badge._id,
8315                                        });
8316                                    }
8317                                }
8318                            });
8319                        }
8320                    });
8321                },
8322            },
8323            '[email protected]': {
8324                template: '<rewards-widget-shell></rewards-widget-shell>',
8325            },
8326            '[email protected]': {
8327                template: '<rewards-widget-shell-single disable-incentives="true" program-filter-enabled="true"></rewards-widget-shell-single>',
8328            },
8329            '[email protected]': {
8330                template: '<achievement-widget></achievement-widget>',
8331            },
8332            '[email protected]': {
8333                template: '<vehicle-exemptions-widget></vehicle-exemptions-widget>',
8334            },
8335            '[email protected]': {
8336                template: '<rideboard-widget></rideboard-widget>',
8337            },
8338            '[email protected]': {
8339                template: '<arp-stat-widget></arp-stat-widget>',
8340            },
8341            '[email protected]': {
8342                templateUrl: '/templates/widgets/triphistory-widget.html',
8343                controller: 'myTripsController',
8344            },
8345            '[email protected]': {
8346                templateUrl: '/templates/widgets/tripplan-widget.html',
8347            },
8348            '[email protected]': {
8349                templateUrl: '/templates/widgets/tripplan-widget2.html',
8350            },
8351            '[email protected]': {
8352                template: '<my-commute-widget></my-commute-widget>',
8353            },
8354            '[email protected]': {
8355                template: '<managed-assets-widget></managed-assets-widget>',
8356            },
8357            '[email protected]': {
8358                template: '<reimbursements-widget></reimbursements-widget>',
8359            },
8360            '[email protected]': {
8361                templateUrl: '/templates/widgets/leaderboard-widget.html',
8362                controller: function ($scope, $rootScope, $timeout, vTriplogreports, vChallenges, CONFIG, $log) {
8363                    $log = $log.getInstance('State: [email protected]');
8364                    $scope.selectedChallenge = null;
8365                    $scope.currentChallenges = [];
8366                    $scope.$watch('selectedChallenge', function (challenge) {
8367                        if (challenge) {
8368                            if (challenge.leaderboards !== 'all') {
8369                                $scope.visibleTab = challenge.leaderboards
8370                                    .split(',')
8371                                    .shift();
8372                            }
8373                            else {
8374                                $scope.visibleTab = 'users';
8375                            }
8376                            vChallenges
8377                                .one(challenge._id)
8378                                .getList('users', { limit: 10 })
8379                                .then(function (users) {
8380                                $scope.users = users;
8381                            });
8382                            vChallenges
8383                                .one(challenge._id)
8384                                .getList('networks', { limit: 10 })
8385                                .then(function (networks) {
8386                                $scope.networks = networks;
8387                            });
8388                            vChallenges
8389                                .one(challenge._id)
8390                                .getList('teams', { limit: 10 })
8391                                .then(function (teams) {
8392                                $scope.teams = teams;
8393                            });
8394                        }
8395                        else {
8396                            $scope.visibleTab = 'users';
8397                            vTriplogreports
8398                                .one('system')
8399                                .getList('leaders', { limit: 10 })
8400                                .then(function (result) {
8401                                $scope.users = result;
8402                            });
8403                            vTriplogreports
8404                                .one('system')
8405                                .getList('networks', { limit: 10 })
8406                                .then(function (result) {
8407                                $scope.networks = result;
8408                            });
8409                        }
8410                    });
8411                    function setChallenges() {
8412                        $scope.currentChallenges = _.filter($scope.sessionData.challenges, { status: 'current' });
8413                        setDefaultChallenge();
8414                    }
8415                    function setDefaultChallenge() {
8416                        $log.debug('legacy challenges widget');
8417                        if (CONFIG.defaultChallengeId) {
8418                            $log.debug('getting defaultChallenge', CONFIG.defaultChallengeId);
8419                            vChallenges.get(CONFIG.defaultChallengeId).then(function onSuccess(defaultChallenge) {
8420                                $log.debug('defaultChallenge', CONFIG.defaultChallengeId, defaultChallenge);
8421                                $scope.defaultChallenge = defaultChallenge;
8422                                $scope.selectedChallenge = defaultChallenge;
8423                            }, function onError(error) {
8424                                $log.error('ERROR : defaultChallenge', CONFIG.defaultChallengeId, error);
8425                            });
8426                        }
8427                        else {
8428                            if (!CONFIG.challengesV2Enabled) {
8429                                $timeout(function () {
8430                                    if ($scope.currentChallenges.length) {
8431                                        $scope.selectedChallenge =
8432                                            $scope.currentChallenges[0];
8433                                    }
8434                                });
8435                            }
8436                        }
8437                    }
8438                    function challengesLoaded() {
8439                        return !!($scope.sessionData.challenges &&
8440                            $scope.sessionData.challenges.length);
8441                    }
8442                    function setup() {
8443                        var timeoutCount = 0;
8444                        var timeoutFn = function () {
8445                            if (timeoutCount < 5) {
8446                                if (challengesLoaded())
8447                                    return setChallenges();
8448                                timeoutCount++;
8449                                return $timeout(timeoutFn, 100);
8450                            }
8451                            else {
8452                                setChallenges();
8453                            }
8454                        };
8455                        return challengesLoaded() ? setChallenges() : timeoutFn();
8456                    }
8457                    setup();
8458                },
8459            },
8460            '[email protected]': {
8461                templateUrl: '/templates/widgets/leaderboard-widget-v2.html',
8462                controller: function ($scope, $rootScope, $timeout, vTriplogreports, vChallenges, CONFIG, $log) {
8463                    $log = $log.getInstance('State: [email protected]');
8464                    $scope.selectedChallenge = null;
8465                    $scope.currentChallenges = [];
8466                    $scope.$watch('selectedChallenge', function (challenge) {
8467                        if (challenge) {
8468                            if (challenge.leaderboards !== 'all') {
8469                                $scope.visibleTab = challenge.leaderboards
8470                                    .split(',')
8471                                    .shift();
8472                            }
8473                            else {
8474                                $scope.visibleTab = 'users';
8475                            }
8476                            vChallenges
8477                                .one(challenge._id)
8478                                .getList('users', { limit: 10 })
8479                                .then(function (users) {
8480                                $scope.users = users;
8481                            });
8482                            vChallenges
8483                                .one(challenge._id)
8484                                .getList('networks', { limit: 10 })
8485                                .then(function (networks) {
8486                                $scope.networks = networks;
8487                            });
8488                            vChallenges
8489                                .one(challenge._id)
8490                                .getList('teams', { limit: 10 })
8491                                .then(function (teams) {
8492                                $scope.teams = teams;
8493                            });
8494                        }
8495                        else {
8496                            $scope.visibleTab = 'users';
8497                            vTriplogreports
8498                                .one('system')
8499                                .getList('leaders', { limit: 10 })
8500                                .then(function (result) {
8501                                $scope.users = result;
8502                            });
8503                            vTriplogreports
8504                                .one('system')
8505                                .getList('networks', { limit: 10 })
8506                                .then(function (result) {
8507                                $scope.networks = result;
8508                            });
8509                        }
8510                    });
8511                    function setChallenges() {
8512                        $scope.currentChallenges = _.filter($scope.sessionData.challenges, { status: 'current' });
8513                        setDefaultChallenge();
8514                    }
8515                    function setDefaultChallenge() {
8516                        $log.debug('legacy challenges widget');
8517                        if (CONFIG.defaultChallengeId) {
8518                            $log.debug('getting defaultChallenge', CONFIG.defaultChallengeId);
8519                            vChallenges.get(CONFIG.defaultChallengeId).then(function onSuccess(defaultChallenge) {
8520                                $log.debug('defaultChallenge', CONFIG.defaultChallengeId, defaultChallenge);
8521                                $scope.defaultChallenge = defaultChallenge;
8522                                $scope.selectedChallenge = defaultChallenge;
8523                            }, function onError(error) {
8524                                $log.error('ERROR : defaultChallenge', CONFIG.defaultChallengeId, error);
8525                            });
8526                        }
8527                        else {
8528                            if (!CONFIG.challengesV2Enabled) {
8529                                $timeout(function () {
8530                                    if ($scope.currentChallenges.length) {
8531                                        $scope.selectedChallenge =
8532                                            $scope.currentChallenges[0];
8533                                    }
8534                                });
8535                            }
8536                        }
8537                    }
8538                    function challengesLoaded() {
8539                        return !!($scope.sessionData.challenges &&
8540                            $scope.sessionData.challenges.length);
8541                    }
8542                    function setup() {
8543                        var timeoutCount = 0;
8544                        var timeoutFn = function () {
8545                            if (timeoutCount < 5) {
8546                                if (challengesLoaded())
8547                                    return setChallenges();
8548                                timeoutCount++;
8549                                return $timeout(timeoutFn, 100);
8550                            }
8551                            else {
8552                                setChallenges();
8553                            }
8554                        };
8555                        return challengesLoaded() ? setChallenges() : timeoutFn();
8556                    }
8557                    setup();
8558                },
8559            },
8560            '[email protected]': {
8561                templateUrl: '/templates/widgets/leaderboard-widget-v2-select.html',
8562                controller: function ($scope, $rootScope, $timeout, vTriplogreports, vChallenges, CONFIG, $log) {
8563                    $log = $log.getInstance('State: [email protected]');
8564                    $scope.selectedChallenge = null;
8565                    $scope.currentChallenges = [];
8566                    $scope.$watch('selectedChallenge', function (challenge) {
8567                        if (challenge) {
8568                            if (challenge.leaderboards !== 'all') {
8569                                $scope.visibleTab = challenge.leaderboards
8570                                    .split(',')
8571                                    .shift();
8572                            }
8573                            else {
8574                                $scope.visibleTab = 'users';
8575                            }
8576                            vChallenges
8577                                .one(challenge._id)
8578                                .getList('users', { limit: 10 })
8579                                .then(function (users) {
8580                                $scope.users = users;
8581                            });
8582                            vChallenges
8583                                .one(challenge._id)
8584                                .getList('networks', { limit: 10 })
8585                                .then(function (networks) {
8586                                $scope.networks = networks;
8587                            });
8588                            vChallenges
8589                                .one(challenge._id)
8590                                .getList('teams', { limit: 10 })
8591                                .then(function (teams) {
8592                                $scope.teams = teams;
8593                            });
8594                        }
8595                        else {
8596                            $scope.visibleTab = 'users';
8597                            vTriplogreports
8598                                .one('system')
8599                                .getList('leaders', { limit: 10 })
8600                                .then(function (result) {
8601                                $scope.users = result;
8602                            });
8603                            vTriplogreports
8604                                .one('system')
8605                                .getList('networks', { limit: 10 })
8606                                .then(function (result) {
8607                                $scope.networks = result;
8608                            });
8609                        }
8610                    });
8611                    function setChallenges() {
8612                        $scope.currentChallenges = _.filter($scope.sessionData.challenges, { status: 'current' });
8613                        setDefaultChallenge();
8614                    }
8615                    function setDefaultChallenge() {
8616                        $log.debug('legacy challenges widget');
8617                        if (CONFIG.defaultChallengeId) {
8618                            $log.debug('getting defaultChallenge', CONFIG.defaultChallengeId);
8619                            vChallenges.get(CONFIG.defaultChallengeId).then(function onSuccess(defaultChallenge) {
8620                                $log.debug('defaultChallenge', CONFIG.defaultChallengeId, defaultChallenge);
8621                                $scope.defaultChallenge = defaultChallenge;
8622                                $scope.selectedChallenge = defaultChallenge;
8623                            }, function onError(error) {
8624                                $log.error('ERROR : defaultChallenge', CONFIG.defaultChallengeId, error);
8625                            });
8626                        }
8627                        else {
8628                            if (!CONFIG.challengesV2Enabled) {
8629                                $timeout(function () {
8630                                    if ($scope.currentChallenges.length) {
8631                                        $scope.selectedChallenge =
8632                                            $scope.currentChallenges[0];
8633                                    }
8634                                });
8635                            }
8636                        }
8637                    }
8638                    function challengesLoaded() {
8639                        return !!($scope.sessionData.challenges &&
8640                            $scope.sessionData.challenges.length);
8641                    }
8642                    function setup() {
8643                        var timeoutCount = 0;
8644                        var timeoutFn = function () {
8645                            if (timeoutCount < 5) {
8646                                if (challengesLoaded())
8647                                    return setChallenges();
8648                                timeoutCount++;
8649                                return $timeout(timeoutFn, 100);
8650                            }
8651                            else {
8652                                setChallenges();
8653                            }
8654                        };
8655                        return challengesLoaded() ? setChallenges() : timeoutFn();
8656                    }
8657                    setup();
8658                },
8659            },
8660            '[email protected]': {
8661                templateUrl: '/templates/widgets/challenge-stats-widget.html',
8662                controller: function ($scope, $rootScope, $timeout, vTriplogreports, vChallenges, CONFIG, $log) {
8663                    $log = $log.getInstance('State: [email protected]');
8664                    $scope.selectedChallenge = null;
8665                    $scope.currentChallenges = [];
8666                    $scope.$watch('selectedChallenge', function (challenge) {
8667                        vChallenges
8668                            .one(challenge._id)
8669                            .one('stats')
8670                            .get()
8671                            .then(function (stats) {
8672                            $scope.challengeStats = stats;
8673                        });
8674                    });
8675                    function setChallenges() {
8676                        $scope.currentChallenges = _.filter($scope.sessionData.challenges, { status: 'current' });
8677                        setDefaultChallenge();
8678                    }
8679                    function setDefaultChallenge() {
8680                        $log.debug('legacy challenges widget');
8681                        if (CONFIG.defaultChallengeId) {
8682                            $log.debug('getting defaultChallenge', CONFIG.defaultChallengeId);
8683                            vChallenges.get(CONFIG.defaultChallengeId).then(function onSuccess(defaultChallenge) {
8684                                $log.debug('defaultChallenge', CONFIG.defaultChallengeId, defaultChallenge);
8685                                $scope.defaultChallenge = defaultChallenge;
8686                                $scope.selectedChallenge = defaultChallenge;
8687                            }, function onError(error) {
8688                                $log.error('ERROR : defaultChallenge', CONFIG.defaultChallengeId, error);
8689                            });
8690                        }
8691                        else {
8692                            if (!CONFIG.challengesV2Enabled) {
8693                                $timeout(function () {
8694                                    if ($scope.currentChallenges.length) {
8695                                        $scope.selectedChallenge =
8696                                            $scope.currentChallenges[0];
8697                                    }
8698                                });
8699                            }
8700                        }
8701                    }
8702                    function challengesLoaded() {
8703                        return !!($scope.sessionData.challenges &&
8704                            $scope.sessionData.challenges.length);
8705                    }
8706                    function setup() {
8707                        var timeoutCount = 0;
8708                        var timeoutFn = function () {
8709                            if (timeoutCount < 5) {
8710                                if (challengesLoaded())
8711                                    return setChallenges();
8712                                timeoutCount++;
8713                                return $timeout(timeoutFn, 100);
8714                            }
8715                            else {
8716                                setChallenges();
8717                            }
8718                        };
8719                        return challengesLoaded() ? setChallenges() : timeoutFn();
8720                    }
8721                    setup();
8722                },
8723            },
8724            '[email protected]': {
8725                templateUrl: '/templates/widgets/user-leaderboard-widget.html',
8726            },
8727            '[email protected]': {
8728                templateUrl: '/templates/widgets/network-leaderboard-widget.html',
8729            },
8730            '[email protected]': {
8731                templateUrl: '/templates/widgets/team-leaderboard-widget.html',
8732            },
8733            '[email protected]': {
8734                templateUrl: '/templates/widgets/user-leaderboard-widget-v2.html',
8735            },
8736            '[email protected]': {
8737                templateUrl: '/templates/widgets/network-leaderboard-widget-v2.html',
8738            },
8739        },
8740    });
8741});

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.