{"version":3,"sources":["endpointStatusService.js","webcomm.constants.js","app.module.js","app.routes.js","loginController.js","activity/activityController.js","activity/activityService.js","channel/channelActivityDirective.js","channel/channelContextController.js","channel/channelController.js","channel/channelFeedController.js","channel/maxMapController.js","channel/privateCallChannelController.js","contacts/contactsController.js","notify/notify.js","reconnect/reconnectDirective.js","settings/settingsController.js","channel/events/callEventController.js","channel/events/endpointStatusChangedController.js","channel/events/SpeakingEventController.js","channel/events/TextMessageEventController.js","channel/map/endpointMapDirective.js","channel/presence/presenceTableController.js","mainController.js","activeChannels.js","sharingLocation.js","truncate.js","channelModel.js","endpointModel.js","feedModel.js","profileModel.js","logDisplayDirective.js","logDisplayLinkDirective.js","anchorInfoService.js","audioService.js","authService.js","connectionHealthService.js","connectionService.js","contactService.js","dispositionService.js","locationService.js","loggerService.js","mapLoaderService.js","muteService.js","notificationService.js","persistenceService.js","privateCallService.js","pttService.js","rememberMeService.js","settingsService.js","textMessageService.js","timeFormattingService.js","tupleDictionaryService.js","userService.js","wtcpjsClientProviderService.js","wtcpjsService.js","clickOutside.js","connectionHealth.js","customAnchorMarker.js","disableRightClick.js","focusDirective.js","resizeDirective.js","scrollGlueDirective.js","touch.js","ui-bootstrap-custom-0.12.0.js","urlMessage.js","disable-debugging.include.js"],"names":["EndpointStatusService","$rootScope","$log","$filter","addSpeaker","channelId","name","clientTime","endpointId","userPriority","self","channelSpeakerMap","getChannelSpeakersMap","broadcastChannelSpeakerChanges","removeSpeaker","speakerCount","Object","keys","length","speakersCommaDelimitedList","map","s","truncateIfNeeded","join","message","concat","eventData","rootScope","$broadcast","filter","allSpeakers","log","debug","$on","event","endpointMap","userName","has","property","hasOwnProperty","parseInt","info","data","type","UP","getSpeakersForChannel","isAnyoneSpeakingOnChannel","this","isHigherOrEqualPrioritySpeakingOnChannel","speakers","mylocalUserPriority","remoteHigherOrEqualPriority","forEach","key","speakerPriority","angular","module","constant","Modernizr","run","svc","createClient","muteService","connectionService","endpointStatusService","notificationService","audioService","newUrl","mainPageRegex","match","id","window","initialLoad","config","$routeProvider","when","controller","templateUrl","otherwise","redirectTo","$scope","$location","wtcpjsService","rememberMeService","authService","showError","error","status","isProfileVisible","isSigningIn","showProfile","profiles","selected","available","isRemembered","savedProfile","get","profile","some","p","profileId","setProfiles","login","server","username","password","then","selectProfile","err","warn","$applyAsync","logout","subscribeToEvents","loginInfo","rememberMe","user","host","appVersion","webcomm_version","getAndResetLogoutError","loginPage","location","reload","loginReset","populateLoginInfo","populateLoginInfoAndLogin","cloud","getAuthUrl","getToken","token","isSuccess","userId","accessToken","url","errorMessage","undefined","Error","remember","forget","setProfile","path","authUrlPath","logoutError","unbindSelectNewProfile","e","directive","scope","replace","controllerAs","activityService","channelModel","_this","isVisible","toggle","$event","activities","setVisible","selectChannel","newActivityCount","factory","timeFormattingService","isPrivateMessage","getGroupNameFromData","Self","destination","displayName","getChannelNameFromId","getChannel","addActivity","eventType","activity","activityCount","time","formatFeedDate","group","groupId","text","service","unshift","MAX_ACTIVITIES","pop","newActivities","visible","$emit","feedEvent","messageData","callerInfo","$interval","link","element","attrs","timeoutId","second","resetTimer","cancel","restrict","bindToController","channel","selectedChannelId","showTimer","channelSpeaking","$timeout","pttService","mapVariableName","isNotSelected","cac","latestSpeakingMessage","activityMessageTimer","unbindChannelSelected","unbindFeedEventReceived","unbindSpeakersChangedEvent","endpointModel","userService","setUserCount","userCount","setEndpointsAndUserCount","channelEndpoints","endpoints","openFullscreenMap","endpointsEnabled","maxEndpointsOnChannel","unbindUsersDisabledOnChannel","max","unbindUsersEnabledOnChannel","unbindUsersLoaded","users","unbindEndpointsLoaded","unbindPresenceUpdated","channelPttService","create","isSelected","isPTTButtonEnabled","canTransmitAudio","getPttIconName","isPttOn","isActivityMessageVisible","muteStatus","muteIconName","onOff","isMuted","getMuteStatus","toggleMute","pttStart","stopImmediatePropagation","pttStop","highlightSpeakingChannel","isHighlighted","arguments","talkingHighlightClass","destroy","select","$parent","mobile","isMainMenuSelected","isMobileFeedVisible","textMessageService","feedModel","privateCallPttService","init","loadFeedEvents","textMessagingDisabledOnChannel","isRxOnlyChannel","setTextMessagingDisabled","val","selectedChannel","feedEvents","getChannelFeed","lastPageStart","Math","lastPage","slice","visibleFeedEvents","unbindFeedEventCallback","push","addAnotherElement","index","feedTimeout","splice","isPrivateCallChannel","userPresent","channelFeed","messageCounter","getUser","participantId","privateTextEnabled","activityMessage","unbindUserPrivateTextEnabled","enabled","unbindUserLeft","unbindUserJoined","userInfo","isActionBarVisible","bargeCall","showTextMessageBox","$evalAsync","sendTextMessage","feedId","isAlert","ep","getMyEndpoint","targetUser","sendPrivateTextMessage","resp","clearAndHideMessageBox","stopPropagation","getSelectedChannel","$watch","newValue","oldValue","closeFullscreenMap","created","removed","privateCallService","vm","$onInit","callRequest","pttPending","calleeNumber","calleeName","_pttPending","activeCallExists","callOfferFromUserExists","callEnded","callAnswered","callActive","isDialing","hidePhoneIcon","closeChannel","active","pttState","phoneButtonClick","callHangup","callId","unbindPrivateCallPTTOff","call","callTooLong","unbindPrivateCallProgress","callState","unbindPrivateCallHangup","unbindReconnecting","reconnecting","setVisibility","contact","callEl","document","getElementById","chatEl","togglePhone","on","toggleClass","isPresent","canTxt","removeClass","addClass","callAlias","canP2P","disableP2P","contactService","anchorInfoService","contactsNav","contacts","start","charCodeAt","end","selfCanP2P","pageSize","aiService","visibleProvider","contactsByLetter","getNavKeys","a","x","String","fromCharCode","navKeys","l","anchor","createAnchor","value","before","getContacts","result","c","currIndex","d","substr","toUpperCase","totalContacts","unbindContactJoined","endpoint","toLowerCase","disposition","privateTxtEnabled","_step","_iterator","_createForOfIteratorHelper","n","done","f","size","privateCallEnabled","add","unbindSelfUpdated","getOwnPropertyNames","unbindContactOffline","clear","$compile","contactEntries","querySelector","clearView","*","console","onScroll","evt","onPageFaultHandling","target","offsetHeight","scrollTop","scrollHeight","after","viewportHeight","floor","handlePageFault","screenHeight","addEventListener","innerHTML","scrollToView","table","scrollIntoView","i","unbindContactLeft","unbindContactDispositionChanged","isBargeCall","makeCall","openPrivateTalkgroup","myEndpoint","addOrUpdatePrivateCallChannel","unbindContactAction","action","$templateRequest","html","template","nameEl","buttons","find","children","attr","$this","hasClass","append","transclude","close","mode","ReconnectController","_classCallCheck","RECONNECT_TIMEOUT_IN_MILLISECONDS","timeoutPromise","isReconnecting","cancelReconnect","settingsService","profileModel","selectedProfile","getSelectedProfile","channels","initialVolume","volume","getVolume","channelIds","getChannelIdsForProfile","locationToggleOn","locationToggleDisabled","webcommVersion","talkGroup","showMaxMessage","getMaxActiveChannelCount","maxActiveChannels","selection","numSelected","isSelectionValid","copyChannels","v","k","toggleLocation","enableToggle","shareLocation","disableToggle","saveSettings","channelsChanged","persistVolume","updateChannelSelection","changeActiveChannels","selectFirstActiveChannel","closeSettings","adjustVolume","unbindSlideEnded","timeSent","getDuration","startedSpeaking","finishedSpeaking","getTime","startTimer","tick","duration","Date","stopTimer","timer","destroyScopes","$destroy","leftOrRight","stretchOrFixed","retry","messageStatus","confirmed","feedMessage","htmlEncode","important","unbindIsReconnecting","_typeof","unbindTextMessageSentError","unbindTextMessageSentConfirmed","unbindTextFeedFinished","EndpointMapController","NgMap","locationService","elementId","mapRightclickListener","timeout","interval","getChannelEndpoints","centerOn","zoom","mapDisabled","unbindSharingLocation","centerMapView","unbindLocationCentered","centerZoomMapOnLoc","unbindEndpointsDisabledOnChannel","unbindEndpointsEnabledOnChannel","remove","_this2","enableConfirm","getMap","evtMap","google","maps","trigger","dispatchEvent","Event","initializeMap","customMarkers","confirm","addListener","isSharingEnabled","setLocationValue","latLng","setPosition","initiallyCenterOnSelfIfSharingLocation","fitAllEndpointsToBounds","_this3","latLngBounds","LatLngBounds","LatLng","la","lo","extend","center","getCenter","lat","lng","fitBounds","loc","setCenter","parseFloat","setZoom","selectedEndpoint","showInfoWindow","flags","getFlags","isSelf","onPhone","sameUser","canChat","hideInfoWindow","hideDetail","_selectedChannel","setLocation","addOrUpdateAndSelectPrivateCallChannel","callEndpoint","closeMaximizedMap","_this4","reloadUsers","getUsers","_myUserInfo","publicTalkgroup","showCallButton","presenceTableLocationClick","getNextLocation","$window","connectionHealthService","mapLoaderService","dispositionService","addChannelToModel","publicChannels","getMyUserName","unbindEndpointsUpdated","privateCallChannels","numPrivateCalls","connectionInfo","latency","serverLag","noMicrophoneNotification","noMicrophone","noMapKeyNotification","mapKey","hideNotification","prop","viewModeBeforeReconnect","assign","getCurrentUser","profileMenu","selectedProfileId","selectedProfileName","profileName","logOut","inboundCall","showSettings","showFullMap","showStatusSelector","viewMode","areChannelsAvailable","areAnyChannelsActive","loginPath","setViewMode","confirmProfileChange","getProfiles","hasMultipleProfiles","openProfileSelect","changeProfile","reconnect","openSettings","mute","allChannelsMuted","unmuteAll","muteAll","privateCallCreated","privateCallRemoved","callOffer","callInfo","answering","answer","callAnswer","hangup","isOpen","set","newStatus","setDisposition","toggled","open","toggleDropdown","preventDefault","googleMapsLoaded","isLoaded","unbindProfileNameChanged","tryAgain","selectedChannelName","unbindChannelPropertiesRecieved","unbindChannelRemoved","unbindPrivateCallChannelsCleared","unbindChannelsUpdated","unbindActiveChannelsChanged","unbindPrivateCallChannelAdded","unbindSettingsClose","unbindOpenFullscrenMap","unbindCloseFullscreenMap","unbindConnectionInfoUpdated","unbindSpeaking","started","unbindMakingCall","unbindCallOfferReceived","unbindCallHangupReceived","unbindPrivateCallChannelClosed","unbindDispositionSet","unbindIdleStart","_myEndpoint","unbindIdleEnd","IdleProvider","idle","Idle","watch","input","out","tail","privateCallChannelId","spc","ChannelData","wtcpjsChannel","isActive","channelName","ready","canReceiveAudio","isSimplex","numEndpoints","update","PrivateCallChannelData","_ChannelData","_super","callType","_inherits","_createSuper","ChannelModel","$q","settingsSvc","_createClass","chan","channelSelections","getChannelSelection","addOrUpdateChannel","fromUserName","toUserName","toCallAlias","barge","pcChan","myUser","getActiveChannelIds","that","activeChannelIds","includes","wtcpjsChannels","every","privateEndpoints","disabledChannels","truncatedChannels","channelUsers","q","_initializing","pendingUserJoined","parseLocation","locElements","split","kv","addToSet","removeFromSet","Endpoint","Map","filterIds","locTimeout","spcActive","clearLocation","em","_addEndpointToChannel","usersMap","userNew","_setEndpointsFlags","_func","updatePropertyWork","newEndpoint","WtcpJs","EndpointFlags","_step2","_iterator2","properties","EndpointModel","Set","silent","endpointPropertyInfo","isLastEndpoint","addEndpoint","endpointInfo","endpointName","endpointFlags","endpointProperties","filterId","addEndpointToChannel","_ep","userMap","feed","FeedModel","MAX_ITEMS","clearFeed","channelFeedEvent","shift","ProfileModel","logger","showLog","hideLog","levelClasses","selectAll","range","createRange","setStart","$","setEnd","getSelection","removeAllRanges","addRange","logMessages","messages","unbindOnShowLogDisplay","ai","AnchorInfo","getNextSet","getNextAnchorOnStartChar","AudioService","wtcpjsClientProviderService","_client","getClient","_log","_rootScope","_settingsService","percentScale","setVolume","AuthResult","errorCode","Number","Code","Description","_authUrl","VoiceStackInfo","UserId","AccessToken","Uri","AuthService","$http","$routeParams","_q","_http","_location","_params","_validDomains","credentials","scopes","method","param","headers","Content-Type","response","Success","Fail","regex","exec","env","domain","oAuthPath","oauthurl","authUrl","ConnectionHealthService","client","onConnectionInfoUpdated","subscribe","ConnectionService","persistenceService","userLoggingIn","forcedDisconnect","accountDisabled","userLoggedInTooMany","isReconnectCanceled","sessionTimedOut","userNoProfiles","unsubscribeChannelActivity","onConnectionClosed","disconnect","onSessionClosed","currentUser","updateUserInfo","func","onChannelActivity","epId","managementServerUrl","connect","awaitSPCActivity","setProfileSuccess","phoneLines","configInfo","reconnectTimeout","logoutWithError","AudioPlayerActive","isOnSecurePage","wsRegex","httpsRegex","isRequestingInsecure","startsWith","serverUrl","defer","isSecure","protocol","createServerUrl","ex","reject","resolve","getUserErrorMessage","promise","_this5","setProfilePromise","setKeyFromProfileResponseAndCreateMapScriptNode","isReconnect","userPassword","setCurrentUser","setEndpointFilterThresholds","_this6","IsClientActive","closeSession","errorCodes","1","7","5","23","52","ContactService","filterTypes","addressBookFilter","aiSvc","isMeOrChannelUser","indexOf","spcFlags","matchIndx","getEndpointInfo","setEndpointAddressBookFilter","participantType","model","currentDisposition","setEndpointProperties","newEPId","LocationService","reset","locSvc","clearTimeout","sendGeoTimeout","loopCount","sharingLocation","sharingGeolocation","setTimeout","loopFrequency","isSharing","stopSharingLocation","Promise","loopGeolocation","sendGeolocation","navigator","geolocation","getCurrentPosition","position","_lat","coords","latitude","toFixed","_lng","longitude","getEndpoint","long","t","formatLocationDate","$provide","loggerProvider","attach","level","fn","isLevelEnabled","now","_len","args","Array","_key","logProvier","apply","logs","enabledLevels","loggingLevels","logLevel","getLoggingLevel","webcomm_logging_level","$get","none","decorator","$delegate","levels","_i","_levels","provider","maxLogLength","date","_len2","_key2","mapScript","MapLoaderService","createElement","googleMapScriptUrl","setAttribute","head","appendChild","parentNode","removeChild","mapprovider","destroyMapScriptNode","createMapScriptNode","MuteService","clientFactory","tempMuteChannels","channelMuteStatusMap","onChannelsUpdated","updateChannels","onActiveChannelsChanged","activeChannelList","muteSavedChannels","onPttStarted","savedMutedChannels","getUserProfileServerValue","getMutedChannels","_sendMutedChannelIds","mutedChannelIds","_saveAndSendMutedChannel","indx","setUserProfileServerValue","muteChannels","NotificationService","_isApplicationActive","onfocus","onblur","bindHandlers","_showNotifications","Notification","requestPermission","notifyIfInactive","unbindCallConnected","notification","onclick","focus","PersistenceService","localStorageService","ROOTKEY","USERKEY","USERPROFILEKEY","USERPROFILESERVERKEY","isSupported","getStorageType","_set","_get","_evict","newKey","_checkKeyExists","_keyException","setPhoneDisposition","_dispositionService","setReadyDisposition","endCall","_channelModel","_feedModel","addChannelFeedEvent","_muteService","restoreTempMute","_endpointModel","_calls","PrivateCallService","notifyCallofferReceived","isRadioUser","activationStatus","Pending","Active","phoneLine","statusMessage","number","activeCallOffer","activeCall","privateCallChannelFilterId","privateCallChannelFilter","spcFilterActive","numberCallIdMap","noCallResource","invalidPhoneLine","createParticipantFilter","p1","p2","setEndpointSPCFilter","initializeEndpoints","privateCall","clearEndpointFilter","unbindLogout","unbindReconnect","onPhoneLineStatusChanged","pcs","onCallProgressRecieved","onCallProgressReceived","onCallOfferReceived","onCallHangupReceived","onCallPTTOffReceived","$scop","line","setEndpointPropertiesPrivateCallFilter","setActivePhoneLines","contactNumber","contactUserName","contactName","myNumber","tempMuteAll","answerCall","callerId","callerUserName","hangupCall","PttService","pttRetryCnt","_pttInit","PTTDown","_notifyPttStarted","channelResponses","_processPttResponse","_pttError","isPttStarted","pttOffHandler","_pttStopImplementation","_stopped","WTCPAudioStatus","isChannelSelected","_pending","_playSound","pttType","_enabled","_rejected","PTTUp","_stopping","$$phase","$apply","soundFileName","src","audio","Audio","play","dur","ceil","PrivateCallPttService","callPTTOn","callPTTOff","RememberMeService","KEY","getAppValue","setAppValue","evictAppValue","SettingsService","shareLoc","setMessageFilters","unbindTextMessageHandler","unbindPrivateMessageHandler","setEndpointPropertiesTextMessageFilter","subscribeToTextMessageEvent","setEndpointPropertiesPrivateMessageFilter","subscribeToPrivateMediaMessageEvent","setPrivateTxtCapableEndpointProp","lookForUrls","m","mIndx","urls","patterns","generateFeedEvent","newEvent","onTextMessageReceived","destinationChannelId","sameEndpoint","sourceEndpointId","sourceUserName","clientSentFeedIds","onPrivateMediaMessageReceived","participants","p2pChannelMap","getTxtData","sendMessage","targetEndpoint","conversationId","txtData","msg","p2pMessage","PrivateTextMessageRequest","Label","sendP2PMessage","textMsgConfirmedDate","webSocket","hours","getHours","minutes","getMinutes","ampm","strTime","days","getDay","fromDate","year","getUTCFullYear","month","getUTCMonth","day","getUTCDate","hour","getUTCHours","minute","getUTCMinutes","getUTCSeconds","TupleDictionaryService","dict","tuple","tupleToString","findIndexOfUser","_users","findIndex","findIndexOfEndpoint","sameUserDiffEndpoint","ep1","ep2","addUserToCollection","ui","_userService","UserInfo","from","_channelUsersMap","values","exc","updateMyDisposition","isPrivateTextEnabled","_provider","_channelId","_cm","_activeDispositionEP","isBusy","isOnPhone","_endpointIndex","getCurrentEndpoint","epIndex","deleted","endpointIndex","sharingEP","_privateCallEnabled","_disposition","allIdle","_curEndpoint","startIndex","getNextEndpoint","UserService","unbindExistingUserJoinedHandler","clearUsers","loadUsers","getChannelUsers","isSelectedChannel","userOnSelectedChannel","userIndex","unbindEndpointLogout","updatedEP","endpointExists","deleteEndpoint","u","version","checkForMicrophone","webCommLicenseUUID","epFilterMaxNumEndpoints","epFilterMaxNumChanEndpointsDisable","Client","audioPlayerActive","licenseUUID","deviceId","getDeviceId","applicationName","loggingLevel","channelFilter","privateCallChannelSelfFilter","random","toString","endpoint_filter","maxnumendpoints","maxnumchanendpointsdisable","tupleDictionaryService","activateChannels","channelsActivated","setEndpointPropertiesChannelActivityFilter","setActiveChannels","deferredForChannelActivationFuncs","resetReadyState","failedChannels","playIncomingAudioSound","secondsPassed","incomingAudioSoundPlayedAt","INCOMING_AUDIO_SOUND_TIMEOUT_SECONDS","createEndpoint","addSilently","newEndPoint","myEndpointId","shareLocationFunc","updateEndpointProperties","state","updateProperties","clearChannelState","clearPrivateCallChannels","clearChannels","clearEndpoints","MAX_ACTIVE_CHANNELS","isSubscribed","channelFilterId","privateTalkgroupSelfFilterId","privateTalkgroupFilterId","addressBookFilterId","channelFilterActive","startSpeaking","put","stopSpeaking","filterEndpoints","setEndpointChannelFilter","subErrorCode","setEndpointsDisabledOnChannel","setEndpointsTruncatedOnChannel","clearEndpointsDisabledOnChannel","clearEndpointsTruncatedOnChannel","clearChannelEndpoints","updatedChannels","clearSelectedChannel","onPTTOff","proxyEP","wcEndpoint","getChannelEndpoint","Gone","updateFlags","Speaking","onEndpointPropertiesReceived","onChannelPropertiesReceived","systemProps","system","transmitAudio","receiveAudio","simplex","onProxyUpdated","changeType","addEmptyChannel","addChannelToCurrentProfile","removeChannel","removeChannelFromCurrentProfile","updateProfileName","activatePhoneLine","areChannelsNewOrChanged","reconnectedWithReducedActiveChannels","$document","elem","onClick","targetAttribute","getAttribute","clickOutside","isToggle","closest","isChild","isInside","unbind","bind","unbindWatcher","oldvalue","parser","CustomMarker","options","el","style","display","visibility","setCustomMarker","prototype","OverlayView","setContent","contents","getDraggable","draggable","setDraggable","getPosition","getProjection","posPixel","fromLatLngToDivPixel","round","offsetWidth","y","left","top","setZIndex","zIndex","getVisible","className","classNames","trim","onAdd","getPanes","overlayMouseTarget","draw","onRemove","linkFunc","orgHtml","varsToWatch","mapController","orgAttrs","orgAttributes","filtered","getOptions","events","getEvents","customMarker","firstElementChild","getGeoLocation","latlng","eventName","addDomListener","addObject","observeAttrSetObj","deleteObject","customMarkerDirective","_$timeout_","_$compile_","Attr2MapOptions","_NgMap_","require","compile","matches","toWatch","$inject","$parse","showFocus","registerForResize","resizeMain","resizePresenceTable","height","moveUpAnimation","findKeyframesRule","moveDownAnimation","deleteRule","appendRule","resizeFeedComments","contentHeight","moduleheadHeight","feedBottom","feedBottomMobile","bottomHeight","is","outerHeight","feedMiddleHeight","total_height","innerHeight","navbar_height","content_height","modulehead_height","popover_screen_height","popoverElement","popover_height","css","rule","ss","styleSheets","cssRules","j","CSSRule","KEYFRAMES_RULE","WEBKIT_KEYFRAMES_RULE","MOZ_KEYFRAMES_RULE","createActivationState","unboundState","initValue","activated","getValue","setValue","oneWayBindingState","getter","twoWayBindingState","setter","createDirective","attrName","direction","priority","$el","scrollIfGlued","activationState","isAttached","scroll","bottom","clientHeight","right","scrollLeft","clientWidth","scrollWidth","$eval","touchEnd","touchStart","passiveeventlisteners","passive","openClass","openScope","dropdownScope","closeDropdown","escapeKeyBind","toggleElement","getToggleElement","contains","which","focusToggleElement","$attrs","dropdownConfig","dropdownService","$animate","getIsOpen","$new","setIsOpen","noop","toggleInvoker","onToggle","$element","wasOpen","isDefined","dropdownCtrl","disabled","aria-haspopup","aria-expanded","newMessage","si","substring","isDebuggingDisabled","$compileProvider","debugInfoEnabled"],"mappings":"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","file":"app.min.js","sourcesContent":["function EndpointStatusService($rootScope, $log, $filter) {\r\n let rootScope = $rootScope;\r\n let log = $log;\r\n let allSpeakers = {}; // this is a hash of hashes.\r\n let filter = $filter;\r\n let mylocalUserPriority; \r\n\r\n log.debug(\"EndpointStatusService initialized\");\r\n\r\n rootScope.$on('endpointModel.presenceUpdated', function(event, endpointMap, channelId, endpointId, userName) {\r\n if ( !endpointMap.has(endpointId) ) {\r\n removeSpeaker(channelId, endpointId);\r\n }\r\n });\r\n\r\n rootScope.$on('wtcpjsService.endpoint.gone', function(event, endpointId) {\r\n // remove the endpoint from any channel they might be speaking on\r\n for (var property in allSpeakers) {\r\n if (allSpeakers.hasOwnProperty(property)) {\r\n removeSpeaker(parseInt(property), endpointId);\r\n }\r\n }\r\n\r\n log.info(\"removed disconnected speaker - \" + endpointId);\r\n });\r\n\r\n rootScope.$on('feedModel.feedEventReceived', function(event, data) {\r\n if (data.type === \"speaking\") {\r\n // check whether we get UP here\r\n // console.log(`current speakers 'UP' ${data.data.UP} or ${data.data['UP']}, isSelf=${data.data.self}`);\r\n addSpeaker(data.channelId, data.name, data.clientTime, data.data.endpointId, data.data.UP, data.data.self);\r\n } else if (data.type === \"end-speaking\") {\r\n removeSpeaker(data.channelId, data.data.endpointId);\r\n }\r\n });\r\n\r\n function addSpeaker (channelId, name, clientTime, endpointId, userPriority, self) {\r\n let channelSpeakerMap = getChannelSpeakersMap(channelId);\r\n channelSpeakerMap[endpointId] = { name, clientTime, userPriority, self };\r\n broadcastChannelSpeakerChanges(channelId, channelSpeakerMap);\r\n }\r\n\r\n function removeSpeaker (channelId, endpointId) {\r\n let channelSpeakerMap = getChannelSpeakersMap(channelId);\r\n if (channelSpeakerMap[endpointId]) {\r\n delete channelSpeakerMap[endpointId];\r\n broadcastChannelSpeakerChanges(channelId, channelSpeakerMap);\r\n }\r\n }\r\n\r\n function broadcastChannelSpeakerChanges (channelId, channelSpeakerMap) {\r\n let speakerCount = Object.keys(channelSpeakerMap).length;\r\n let speakersCommaDelimitedList = Object.keys(channelSpeakerMap).map(s => truncateIfNeeded(channelSpeakerMap[s].name)).join(', ');\r\n let message = `${speakersCommaDelimitedList} ${ speakerCount > 1 ? 'are' : 'is'} speaking.`;\r\n let eventData = { channelId, speakerCount, speakersCommaDelimitedList, message };\r\n\r\n rootScope.$broadcast('endpointStatusService.speakersChanged', eventData);\r\n //logChannelSpeakers(eventData);\r\n }\r\n\r\n function truncateIfNeeded(name) {\r\n return filter('truncate')(name, 20);\r\n }\r\n\r\n function getChannelSpeakersMap(channelId) {\r\n let channelSpeakerMap = allSpeakers[channelId] = allSpeakers[channelId] || {}; // init and return\r\n return channelSpeakerMap;\r\n }\r\n\r\n function logChannelSpeakers(data) {\r\n log.info(\"speakers: \", data);\r\n }\r\n\r\n return {\r\n getSpeakersForChannel(channelId) { return getChannelSpeakersMap(channelId); },\r\n\r\n /**\r\n * Returns a boolean whether someone is currently speaking on a channel\r\n * @param channelId\r\n * @returns {boolean}\r\n */\r\n\r\n isAnyoneSpeakingOnChannel(channelId) { return Object.keys(this.getSpeakersForChannel(channelId)).length > 0; },\r\n\r\n /**\r\n * check whether there is any speaker having equal or higher priority\r\n * -- keep this future extension purpose (disable PTT button when equal or higher priority user speaks on simplex channnel)\r\n * @param channelId \r\n */\r\n isHigherOrEqualPrioritySpeakingOnChannel(channelId) {\r\n var speakers = this.getSpeakersForChannel(channelId);\r\n let mylocalUserPriority = 10; // default \r\n let remoteHigherOrEqualPriority = 10; // set default priority\r\n Object.keys(speakers).forEach(function(key) {\r\n if(speakers[key].hasOwnProperty(\"userPriority\")) {\r\n var speakerPriority = parseInt(speakers[key].userPriority);\r\n if(speakers[key].self) {\r\n mylocalUserPriority = speakerPriority;\r\n }\r\n else if (speakerPriority < remoteHigherOrEqualPriority) {\r\n remoteHigherOrEqualPriority = speakerPriority; ; \r\n }\r\n }\r\n // console.log(key, speakers[key]);\r\n });\r\n \r\n return remoteHigherOrEqualPriority < mylocalUserPriority; }\r\n }\r\n}\r\n\r\nangular\r\n .module('webcomm')\r\n .factory('endpointStatusService', ['$rootScope', '$log', '$filter', EndpointStatusService]);","angular.module(\"webcomm.constants\", [])\n.constant(\"version\", \"5.19.0\");\n","//angular.module('webcomm', ['ngRoute', 'LocalStorageModule', 'luegg.directives', 'uiGmapgoogle-maps', 'nemLogging'])\r\nangular.module('webcomm', ['ngRoute', 'LocalStorageModule', 'luegg.directives', 'rzModule', 'ngMap', 'ngAnimate', 'ui.bootstrap', 'ngIdle', 'webcomm.constants'])\r\n .constant('Modernizr', Modernizr)\r\n .run(['wtcpjsClientProviderService', function(svc) {\r\n svc.createClient();\r\n }])\r\n .run([\r\n '$rootScope',\r\n '$log',\r\n 'muteService',\r\n 'connectionService',\r\n 'endpointStatusService',\r\n 'notificationService',\r\n 'audioService', function (\r\n $rootScope,\r\n $log,\r\n muteService,\r\n connectionService,\r\n endpointStatusService,\r\n notificationService,\r\n audioService) { // a lot of these are included here so they startup with app\r\n\r\n $log.debug('application initialized');\r\n //$log.info('$location.path:', $location.path());\r\n\r\n // change the body ID for the page\r\n $rootScope.$on('$locationChangeSuccess', function(event, newUrl) {\r\n var mainPageRegex = /#\\/main/;\r\n if (newUrl.match(mainPageRegex)) {\r\n $rootScope.id = 'main-page';\r\n } else {\r\n $rootScope.id = 'login-page';\r\n // this is resets the global in app.global.js when the app restarts - prevents history popup.\r\n window.initialLoad = true;\r\n }\r\n });\r\n }]);\r\n","angular.module('webcomm').config(['$routeProvider', function ($routeProvider) {\r\n $routeProvider\r\n .when('/main/:mode*?', {\r\n controller: 'MainController',\r\n templateUrl: 'app/main/main.html' \r\n })\r\n .when('/:mode?', {\r\n controller: 'LoginController',\r\n templateUrl: 'app/login/login.html'\r\n })\r\n .otherwise({\r\n redirectTo: '/'\r\n });\r\n}]);","angular\r\n .module('webcomm')\r\n .controller(\r\n \"LoginController\",\r\n [ '$scope', '$location', '$log', 'connectionService', 'wtcpjsService', 'rememberMeService', 'authService',\r\n function ($scope, $location, $log, connectionService, wtcpjsService, rememberMeService, authService) {\r\n\r\n $log.info('LoginController initialized - logging out');\r\n $scope.$applyAsync(function($scope) {\r\n $scope.initialLoad = true;\r\n });\r\n\r\n connectionService.logout();\r\n wtcpjsService.subscribeToEvents();\r\n\r\n // remembered? load\r\n $scope.loginInfo = rememberMeService.isRemembered() ? {\r\n rememberMe: true,\r\n name: rememberMeService.get().user,\r\n server: rememberMeService.get().server,\r\n } : {\r\n server: $location.host()\r\n };\r\n\r\n $scope.status = {\r\n appVersion: window.webcomm_version,\r\n error: connectionService.getAndResetLogoutError(),\r\n isSigningIn: false,\r\n isProfileVisible: false\r\n };\r\n\r\n $scope.loginPage = function () {\r\n $log.debug(\"Back To main Page\");\r\n //connectionService.logout();\r\n window.location.reload(true);\r\n };\r\n\r\n $scope.loginReset = function() {\r\n $scope.status.error = false;\r\n connectionService.logout();\r\n };\r\n\r\n $scope.populateLoginInfo = function (info) {\r\n $scope.loginInfo = info;\r\n $scope.loginInfo.profile = '';\r\n };\r\n\r\n $scope.populateLoginInfoAndLogin = function (info) {\r\n $scope.populateLoginInfo(info);\r\n $scope.login();\r\n };\r\n\r\n $scope.cloud = {\r\n status: 'pending'\r\n };\r\n\r\n authService.getAuthUrl()\r\n .then((data) => {\r\n if (data) {\r\n $scope.cloud = {\r\n server: data,\r\n status: 'ready'\r\n };\r\n } else {\r\n $scope.cloud.server = null;\r\n $scope.cloud.status = 'ready';\r\n }\r\n })\r\n .catch((err) => {\r\n showError(err.message);\r\n })\r\n\r\n function showError(error) {\r\n $scope.status.isProfileVisible = false;\r\n $scope.status.isSigningIn = false;\r\n $scope.status.error = error;\r\n }\r\n\r\n function showProfile() {\r\n $scope.status.isProfileVisible = true;\r\n\r\n // default to the first one\r\n $scope.profiles.selected = $scope.profiles.available[0];\r\n if (rememberMeService.isRemembered()) {\r\n let savedProfile = rememberMeService.get().profile;\r\n // ..or change to saved one if it matches our set\r\n if (savedProfile && $scope.profiles.available.some(p => p.profileId === savedProfile.profileId)) {\r\n $scope.profiles.selected = savedProfile;\r\n }\r\n }\r\n }\r\n\r\n $scope.login = function () {\r\n $log.debug(\"loginController.login\");\r\n $scope.status.isSigningIn = true;\r\n $scope.status.error = false;\r\n\r\n let username = $scope.loginInfo.name,\r\n password = $scope.loginInfo.password,\r\n server = $scope.loginInfo.server;\r\n\r\n if ($scope.cloud.server)\r\n {\r\n // call to provisioning server with username and password\r\n // get back the UserID and Access Token,\r\n // log in with those.\r\n authService\r\n .getToken($scope.cloud.server, $scope.loginInfo.name, $scope.loginInfo.password)\r\n .then(token => {\r\n $log.debug(\"got provisioning token\", token);\r\n\r\n if (token.isSuccess) {\r\n username = token.userId;\r\n password = token.accessToken;\r\n server = token.url;\r\n\r\n $log.debug(`logging into ${server} with username ${username} and password ${password}`);\r\n login(server, username, password);\r\n }\r\n else {\r\n showError(token.errorMessage);\r\n }\r\n })\r\n .catch(err => {\r\n showError(err.message);\r\n });\r\n }\r\n else {\r\n login(server, username, password);\r\n }\r\n };\r\n\r\n function setProfiles(profiles) {\r\n $log.debug(\"login success. Profiles: \", profiles);\r\n $scope.status.error = false;\r\n $scope.profiles = {\r\n available: profiles,\r\n selected: profiles[0] // select the first one\r\n };\r\n }\r\n\r\n function login(server, username, password) {\r\n connectionService.login(server, username, password)\r\n .then(\r\n function (profiles) { // success\r\n setProfiles(profiles);\r\n\r\n // if there's only one profile, skip profile selection step.\r\n if (profiles.length === 1) {\r\n $log.debug(\"single profile found - logging in\");\r\n $scope.selectProfile(username, password);\r\n } else {\r\n showProfile();\r\n }\r\n },\r\n function (err) { // error\r\n $log.warn(\"loginController login: \", err);\r\n showError(err);\r\n // $scope.status.isSigningIn = false;\r\n }\r\n )\r\n .finally(() => $scope.status.isSigningIn = false);\r\n };\r\n\r\n $scope.selectProfile = function (username, password) {\r\n if (!username) {\r\n username = $scope.loginInfo.name;\r\n password = $scope.loginInfo.password;\r\n }\r\n\r\n $log.debug(\"loginController.selectProfile\");\r\n\r\n if ($scope.profiles == undefined) {\r\n throw Error(\"No profiles defined\"); // this should be handled with a message\r\n }\r\n\r\n if ($scope.loginInfo.rememberMe) {\r\n rememberMeService.remember($scope.loginInfo.name, $scope.loginInfo.server, $scope.profiles.selected);\r\n } else {\r\n rememberMeService.forget();\r\n }\r\n\r\n connectionService.setProfile(\r\n username,\r\n password,\r\n $scope.profiles.selected\r\n )\r\n .then(() => $location.path('/main' + authService.authUrlPath))\r\n .catch(err => showError(err));\r\n }\r\n\r\n var logoutError = $scope.$on('logoutError', function (event, error) {\r\n $scope.status.error = error;\r\n $log.info('logged out - ' + error);\r\n });\r\n\r\n var unbindSelectNewProfile = $scope.$on('connectionService.selectNewProfile', (e, profiles) => {\r\n setProfiles(profiles);\r\n showProfile();\r\n });\r\n\r\n $scope.$on('destroy', function() {\r\n logoutError();\r\n unbindSelectNewProfile();\r\n });\r\n\r\n\r\n}]);","angular.module('webcomm')\r\n .directive('activity', function() {\r\n return {\r\n scope: {\r\n //items: '='\r\n },\r\n templateUrl: 'app/main/activity/activity.html',\r\n replace: true,\r\n controller: 'ActivityController',\r\n controllerAs: 'activity'\r\n };\r\n })\r\n .controller('ActivityController', [\r\n 'activityService', 'channelModel', function (activityService, channelModel) {\r\n this.isVisible = false;\r\n this.toggle = ($event) => {\r\n if (this.activities.length > 0) {\r\n this.isVisible = !this.isVisible;\r\n activityService.setVisible(this.isVisible);\r\n }\r\n }\r\n\r\n this.selectChannel = (channelId) => {\r\n if(channelId !== 0) {\r\n channelModel.selectChannel(channelId);\r\n }\r\n }\r\n\r\n this.newActivityCount = activityService.newActivityCount;\r\n this.activities = activityService.activities;\r\n }\r\n ]);","angular\r\n .module('webcomm')\r\n .factory(\r\n 'activityService',\r\n ['$rootScope', '$log', 'channelModel','timeFormattingService',\r\n ($rootScope, $log, channelModel, timeFormattingService) => {\r\n var newActivities = 0;\r\n var activityCount = 0;\r\n var isVisible = false;\r\n const MAX_ACTIVITIES = 5000;\r\n\r\n var service = {\r\n newActivityCount() {\r\n return newActivities;\r\n },\r\n setVisible(visible) {\r\n isVisible = visible;\r\n if (isVisible) {\r\n newActivities = 0;\r\n $rootScope.$emit('timeForResize');\r\n }\r\n },\r\n activities: []\r\n };\r\n\r\n function isPrivateMessage(channelId) {\r\n return channelId <= 0;\r\n }\r\n\r\n // needs work for private call data\r\n function getGroupNameFromData(data) {\r\n if(data.Self) {\r\n return data.destination.displayName;\r\n } else {\r\n return \"You\";\r\n }\r\n }\r\n\r\n function getChannelNameFromId(channelId) {\r\n return channelModel.getChannel(channelId).name;\r\n }\r\n\r\n function addActivity(channelId, clientTime, eventType, name, message, data) {\r\n\r\n var activity = {\r\n id: activityCount++,\r\n type: '',\r\n time: timeFormattingService.formatFeedDate(clientTime),\r\n name: name,\r\n group: isPrivateMessage(channelId) && data ? getGroupNameFromData(data) : getChannelNameFromId(channelId),\r\n groupId: channelId,\r\n text: message\r\n };\r\n\r\n if(eventType === \"end-speaking\") {\r\n activity.type = \"audio\";\r\n } else if ( eventType.match('call-')) {\r\n activity.type = \"call\";\r\n } else {\r\n activity.type = \"text\";\r\n }\r\n\r\n service.activities.unshift(activity);\r\n\r\n // remove last element if we hit size limit\r\n if (service.activities.length > MAX_ACTIVITIES) {\r\n service.activities.pop();\r\n }\r\n\r\n if (!isVisible) {\r\n newActivities++;\r\n }\r\n }\r\n\r\n $rootScope.$on('feedModel.feedEventReceived', function(event, feedEvent) {\r\n //$log.info('activity - feedEventReceived', feedEvent);\r\n switch(feedEvent.type) {\r\n case \"text-message\":\r\n addActivity(\r\n feedEvent.channelId,\r\n feedEvent.clientTime,\r\n feedEvent.type,\r\n feedEvent.name,\r\n feedEvent.data.message,\r\n feedEvent.data.messageData\r\n );\r\n break;\r\n case \"end-speaking\":\r\n case \"call-started\":\r\n addActivity(\r\n feedEvent.channelId,\r\n feedEvent.clientTime,\r\n feedEvent.type,\r\n feedEvent.name,\r\n feedEvent.data.message\r\n );\r\n break;\r\n case \"call-offer\":\r\n addActivity(\r\n feedEvent.channelId,\r\n feedEvent.clientTime,\r\n feedEvent.type,\r\n feedEvent.name,\r\n 'Trying to call ',\r\n feedEvent.data.callerInfo\r\n );\r\n break;\r\n }\r\n });\r\n\r\n $rootScope.$on('ConnectionService.logout', (event, data) => {\r\n newActivities = 0;\r\n service.activities = [];\r\n });\r\n\r\n $log.debug('activityService initialized');\r\n return service;\r\n }\r\n ]);","(function(angular) { \r\n 'use strict';\r\n \r\n angular\r\n .module('webcomm')\r\n .directive('channelActivity', ['$interval', function ($interval) {\r\n\r\n function link(scope, element, attrs ) {\r\n var second = 0;\r\n var timeoutId;\r\n\r\n scope.resetTimer = function() {\r\n second = 0;\r\n };\r\n\r\n scope.$on('$destroy', function(){\r\n $interval.cancel(timeoutId);\r\n });\r\n\r\n timeoutId = $interval(function() {\r\n second++;\r\n }, 1000);\r\n }\r\n\r\n return {\r\n link: link,\r\n restrict: 'E',\r\n scope: {},\r\n bindToController: {\r\n channel: '=',\r\n selectedChannelId: '=',\r\n showTimer: '=',\r\n channelSpeaking: '&onChannelSpeaking'\r\n },\r\n templateUrl: 'app/main/channel/channelActivity.html',\r\n controller: 'ChannelActivityController',\r\n controllerAs: 'cac'\r\n };\r\n }])\r\n .controller(\r\n 'ChannelActivityController', [\r\n '$scope',\r\n '$log',\r\n '$timeout',\r\n '$filter',\r\n 'pttService',\r\n 'muteService',\r\n 'channelModel',\r\n 'endpointStatusService',\r\n function($scope, $log, $timeout, $filter, pttService, muteService, channelModel, endpointStatusService) {\r\n \r\n var cac = this;\r\n \r\n cac.activity = {\r\n message: '',\r\n isVisible: false\r\n };\r\n\r\n var latestSpeakingMessage = \"\";\r\n \r\n var activityMessageTimer = 0;\r\n\r\n function mapVariableName(isNotSelected) {\r\n return {isNotSelected};\r\n }\r\n\r\n var unbindChannelSelected = $scope.$on('channelModel.channelSelected', function(event, channel) {\r\n // only change the highlight if on an unselected channel\r\n cac.channelSpeaking(mapVariableName(cac.channel.id !== channel.id && endpointStatusService.isAnyoneSpeakingOnChannel(cac.channel.id)));\r\n });\r\n\r\n var unbindFeedEventReceived = $scope.$on('feedModel.feedEventReceived', function(event, data) {\r\n if (data.channelId === cac.channel.id) {\r\n cac.activity.isVisible = true;\r\n\r\n if (data.type === \"text-message\") {\r\n\r\n cac.activity.message = $filter('truncate')(data.name) + \" sent text.\";\r\n\r\n if (activityMessageTimer) {\r\n $timeout.cancel(activityMessageTimer);\r\n }\r\n\r\n // hide notification after 3 seconds\r\n activityMessageTimer = $timeout(\r\n function() {\r\n cac.activity.message = latestSpeakingMessage;\r\n cac.activity.isVisible = !!latestSpeakingMessage ? true : false;\r\n },\r\n 3000\r\n );\r\n }\r\n }\r\n });\r\n\r\n var unbindSpeakersChangedEvent = $scope.$on('endpointStatusService.speakersChanged', function (event, data) {\r\n if (data.channelId === cac.channel.id) {\r\n\r\n if (data.speakerCount) {\r\n cac.activity.isVisible = true;\r\n latestSpeakingMessage = cac.activity.message = data.message;\r\n\r\n // only change the highlight if on an unselected channel\r\n if (cac.selectedChannelId && data.channelId !== cac.selectedChannelId) {\r\n //$log.debug(\"highlighting by speakersChanged: \", data.channelId);\r\n cac.channelSpeaking(mapVariableName(true));\r\n }\r\n }\r\n else {\r\n latestSpeakingMessage = cac.activity.message = \"\";\r\n cac.activity.isVisible = false;\r\n cac.channelSpeaking(mapVariableName(false));\r\n }\r\n }\r\n });\r\n\r\n $scope.$on(\r\n \"$destroy\",\r\n function(event) {\r\n unbindChannelSelected();\r\n unbindFeedEventReceived();\r\n unbindSpeakersChangedEvent();\r\n $timeout.cancel(activityMessageTimer);\r\n }\r\n );\r\n }]);\r\n})(angular);","angular\r\n .module('webcomm')\r\n .controller('ChannelContextController', [\r\n '$scope', \r\n '$log', \r\n 'endpointModel',\r\n 'userService',\r\n function ($scope, $log, endpointModel, userService) {\r\n $log.debug('Loading ChannelContextController');\r\n\r\n function setUserCount() {\r\n $scope.userCount = userService.userCount;\r\n }\r\n\r\n function setEndpointsAndUserCount(channelEndpoints) {\r\n $scope.endpoints = channelEndpoints;\r\n setUserCount();\r\n }\r\n\r\n $scope.status = {};\r\n $scope.openFullscreenMap = function() {\r\n $scope.$emit('map.openFullscreenMap');\r\n };\r\n\r\n $scope.userCount = 0;\r\n\r\n $scope.endpointsEnabled = true;\r\n $scope.maxEndpointsOnChannel = 9999;\r\n\r\n var unbindUsersDisabledOnChannel = $scope.$on('endpointModel.endpointsDisabledOnChannel', function(e, channelId, max) {\r\n if(channelId === $scope.channel.id) {\r\n $scope.endpointsEnabled = false;\r\n $scope.maxEndpointsOnChannel = max;\r\n }\r\n });\r\n\r\n var unbindUsersEnabledOnChannel = $scope.$on('endpointModel.endpointsEnabledOnChannel', function(e, channelId) {\r\n if(channelId === $scope.channel.id) {\r\n $scope.endpointsEnabled = true;\r\n }\r\n });\r\n\r\n var unbindUsersLoaded = $scope.$on('userService.usersLoaded', function(e, users) {\r\n setUserCount();\r\n });\r\n\r\n var unbindEndpointsLoaded = $scope.$on('endpointModel.endpointsLoaded', function (e, channelEndpoints) {\r\n setEndpointsAndUserCount(channelEndpoints);\r\n });\r\n\r\n var unbindPresenceUpdated = $scope.$on('endpointModel.presenceUpdated', function(event, channelEndpoints) {\r\n setEndpointsAndUserCount(channelEndpoints);\r\n });\r\n\r\n $scope.$on('$destroy', function () {\r\n unbindUsersEnabledOnChannel();\r\n unbindUsersDisabledOnChannel();\r\n unbindEndpointsLoaded();\r\n unbindPresenceUpdated();\r\n unbindUsersLoaded();\r\n\r\n $log.debug('ChannelContextController destroyed');\r\n });\r\n }]);","angular\r\n .module('webcomm')\r\n .controller(\r\n 'ChannelController', [\r\n '$scope',\r\n '$log',\r\n '$timeout',\r\n 'pttService',\r\n 'muteService',\r\n 'channelModel',\r\n function($scope, $log, $timeout, pttService, muteService, channelModel) {\r\n let channelPttService = pttService.create($scope.channel.id);\r\n\r\n $scope.status = {\r\n isSelected() {\r\n return $scope.selectedChannelId === $scope.channel.id;\r\n },\r\n isPTTButtonEnabled() {\r\n return channelPttService.canTransmitAudio();\r\n },\r\n getPttIconName() {\r\n return channelPttService.getPttIconName(this.isSelected());\r\n },\r\n isPttOn() {\r\n return channelPttService.isPttOn();\r\n },\r\n isActivityMessageVisible: false\r\n }\r\n\r\n $scope.muteStatus = {\r\n muteIconName() {\r\n var onOff = this.isMuted() ? \"off\" : \"on\";\r\n return onOff + \"_\" + $scope.status.isSelected();\r\n },\r\n isMuted() {\r\n return muteService.getMuteStatus($scope.channel.id);\r\n },\r\n toggleMute() {\r\n muteService.toggleMute($scope.channel.id);\r\n }\r\n };\r\n\r\n $scope.pttStart = function($event) {\r\n // this is to stop the system from interpreting the PTT click as a channel select\r\n if ($event) {\r\n $event.stopImmediatePropagation();\r\n }\r\n\r\n if (!channelPttService.isPttOn()) {\r\n channelPttService.pttStart();\r\n }\r\n };\r\n\r\n $scope.pttStop = function($event) {\r\n // this is to stop the system from interpreting the PTT click as a channel select\r\n if ($event) {\r\n $event.stopImmediatePropagation();\r\n }\r\n\r\n channelPttService.pttStop();\r\n };\r\n\r\n $scope.highlightSpeakingChannel = function(isHighlighted = true) {\r\n $scope.status.talkingHighlightClass = isHighlighted ? \"talking5\" : \"\";\r\n }\r\n\r\n $scope.$on(\r\n \"$destroy\",\r\n function(event) {\r\n channelPttService.destroy();\r\n }\r\n );\r\n\r\n $scope.select = function(channelId) {\r\n if (!$scope.status.isSelected()) {\r\n $scope.isMobileFeedVisible = true;\r\n channelModel.selectChannel(channelId);\r\n } else { // Barf, i hate this, but best I can do for now --scott s\r\n $scope.$parent.mobile.isMainMenuSelected = false;\r\n }\r\n };\r\n }\r\n ]);\r\n","angular\r\n .module('webcomm')\r\n .controller('ChannelFeedController', [\r\n '$scope',\r\n '$log',\r\n '$timeout',\r\n 'textMessageService',\r\n 'feedModel',\r\n 'endpointModel',\r\n 'userService',\r\n 'pttService',\r\n 'privateCallPttService',\r\n function ($scope, $log, $timeout, textMessageService, feedModel, endpointModel, userService, pttService, privateCallPttService) {\r\n var selectedChannel;\r\n let channelPttService = pttService.create($scope.channel.id);\r\n let unbindFeedEventCallback;\r\n let feedTimeout;\r\n let userPresent = true;\r\n\r\n function init() {\r\n loadFeedEvents($scope.channel.id);\r\n //$log.debug(\"ChannelFeedController initialized\");\r\n //may miss the broadcasting message 'channelModel.channelSelected' before channelFeedController is ready. \r\n //so init the textMessaingDisabledOnChannel[$scope.channel.id]\r\n $scope.textMessagingDisabledOnChannel[$scope.channel.id] = channelPttService.isRxOnlyChannel();\r\n }\r\n\r\n function setTextMessagingDisabled(val) {\r\n $scope.textMessagingDisabledOnChannel[selectedChannel.id] = val;\r\n }\r\n\r\n function loadFeedEvents(channelId) {\r\n // load the last X events at first, then start loading previous ones incrementally\r\n let feedEvents = feedModel.getChannelFeed(channelId);\r\n\r\n // grab the last page\r\n let lastPageStart = Math.max(feedEvents.length - 13, 0);\r\n let lastPage = feedEvents.slice(lastPageStart);\r\n $scope.visibleFeedEvents = lastPage;\r\n\r\n if (lastPageStart > 0) {\r\n unbindFeedEventCallback = $scope.$on('feedModel.feedEventReceived', (event, feedEvent) => {\r\n if (feedEvent.channelId === channelId)\r\n $scope.visibleFeedEvents.push(feedEvent);\r\n })\r\n addAnotherElement(channelId, feedEvents, lastPageStart - 1);\r\n }\r\n else {\r\n $scope.visibleFeedEvents = feedModel.getChannelFeed(channelId);\r\n }\r\n }\r\n\r\n function addAnotherElement(channelId, feedEvents, index) {\r\n feedTimeout = $timeout(() => {\r\n $scope.visibleFeedEvents.splice(0, 0, feedEvents[index])\r\n index--;\r\n if (index > 0)\r\n addAnotherElement(channelId, feedEvents, index);\r\n else {\r\n $scope.visibleFeedEvents = feedModel.getChannelFeed(channelId);\r\n unbindFeedEventCallback();\r\n }\r\n }, 5);\r\n }\r\n\r\n function isPrivateCallChannel(channelId) {\r\n return channelId < 0;\r\n }\r\n\r\n // Scope variables\r\n\r\n $scope.textMessagingDisabledOnChannel = {};\r\n $scope.channelFeed = { message: '' };\r\n $scope.messageCounter = 0;\r\n\r\n var unbindChannelSelected = $scope.$on('channelModel.channelSelected', function (event, channel) {\r\n unbindFeedEventCallback && unbindFeedEventCallback();\r\n feedTimeout && $timeout.cancel(feedTimeout);\r\n\r\n // release existing resources and re-point ptt service to correct channel\r\n $log.debug(\"ChannelFeedController channel changed - \", channel);\r\n channelPttService.destroy();\r\n if(channel.id < 0) {\r\n channelPttService = privateCallPttService.create(channel.id);\r\n } else {\r\n channelPttService = pttService.create(channel.id);\r\n }\r\n selectedChannel = channel;\r\n\r\n loadFeedEvents(channel.id);\r\n\r\n if (channel.id > 0) {\r\n setTextMessagingDisabled(channelPttService.isRxOnlyChannel());\r\n }\r\n });\r\n\r\n var unbindUsersLoaded = $scope.$on('userService.usersLoaded', () => {\r\n // If userService.usersLoaded is fired but a channel hasn't been selected yet, then this is the initial load of\r\n // of endpoints and this controller wasn't loaded yet to capture the channel select\r\n if (selectedChannel && selectedChannel.id < 0 && !$scope.textMessagingDisabledOnChannel[selectedChannel.id]) {\r\n let user = userService.getUser(selectedChannel.participantId);\r\n if (selectedChannel.participantId && user && user.privateTextEnabled) {\r\n setTextMessagingDisabled(false);\r\n } else {\r\n setTextMessagingDisabled(true);\r\n }\r\n }\r\n });\r\n\r\n var unbindSpeakersChangedEvent = $scope.$on('endpointStatusService.speakersChanged', function (event, data) {\r\n if (data.channelId === $scope.channel.id) {\r\n $scope.status.activityMessage = data.speakerCount ? data.message : \"\"; // only show message if there are speakers\r\n }\r\n });\r\n\r\n var unbindUserPrivateTextEnabled = $scope.$on('userService.privateTextEnabled', (e, user, enabled) => {\r\n if($scope.channel.id < 0 && $scope.channel.participantId === user.userName) {\r\n $scope.textMessagingDisabledOnChannel[$scope.channel.id] = !enabled;\r\n }\r\n });\r\n\r\n var unbindUserLeft = $scope.$on('userService.userLeft', (e, user, channelId) => {\r\n if(isPrivateCallChannel(channelId)) {\r\n userPresent = false;\r\n setTextMessagingDisabled(true);\r\n }\r\n });\r\n\r\n var unbindUserJoined = $scope.$on('userService.userJoined', (e, userInfo) => {\r\n if(userInfo.userName === $scope.channel.participantId && !userPresent) {\r\n userPresent = true;\r\n setTextMessagingDisabled(false);\r\n }\r\n });\r\n\r\n // $scope.eventFeed = function() {\r\n // let feed = feedModel.getChannelFeed($scope.channel.id);\r\n // //console.error(feed);\r\n // return feed;\r\n //\r\n // };\r\n\r\n $scope.status = {\r\n activityMessage: '',\r\n isActionBarVisible: true,\r\n isPTTButtonEnabled: function () {\r\n return $scope.channel.bargeCall || channelPttService.canTransmitAudio();\r\n },\r\n getPttIconName() {\r\n return channelPttService.getPttIconName(false);\r\n },\r\n isPttOn() {\r\n return channelPttService.isPttOn();\r\n },\r\n showTextMessageBox() {\r\n this.isActionBarVisible = false;\r\n $scope.$evalAsync(() => {\r\n $scope.$emit('timeForResize');\r\n });\r\n }\r\n };\r\n\r\n $scope.sendTextMessage = function (message, feedId, isAlert) {\r\n\r\n if( $scope.channel.id < 0 ) {\r\n let ep = endpointModel.getMyEndpoint();\r\n let targetUser = userService.getUser($scope.channel.participantId);\r\n textMessageService.sendPrivateTextMessage($scope.channel, targetUser, ep, message, feedId, isAlert)\r\n .then((resp) => {\r\n $scope.$broadcast('textMessageSentConfirmed', resp);\r\n })\r\n .catch((err) => {\r\n $scope.$broadcast('textMessageSentError', err.feedId, err.errorMessage);\r\n });\r\n } else {\r\n textMessageService.sendTextMessage($scope.channel, endpointModel.getMyEndpoint(), message, feedId, isAlert)\r\n .then((resp) => {\r\n $scope.$broadcast('textMessageSentConfirmed', resp);\r\n })\r\n .catch((err) => {\r\n $scope.$broadcast('textMessageSentError', err.feedId, err.errorMessage);\r\n });\r\n }\r\n $scope.clearAndHideMessageBox();\r\n $scope.messageCounter++;\r\n };\r\n\r\n $scope.clearAndHideMessageBox = function () {\r\n $scope.channelFeed.message = '';\r\n $scope.status.isActionBarVisible = true;\r\n }\r\n\r\n\r\n $scope.pttStart = function ($event) {\r\n // this is to stop the system from interpreting the PTT click as a channel select\r\n if ($event) {\r\n $event.stopImmediatePropagation();\r\n }\r\n if (!channelPttService.isPttOn()) {\r\n channelPttService.pttStart();\r\n }\r\n };\r\n\r\n $scope.pttStop = function ($event) {\r\n // this is to stop the system from interpreting the PTT click as a channel select\r\n if ($event) {\r\n $event.stopImmediatePropagation();\r\n }\r\n channelPttService.pttStop();\r\n };\r\n\r\n $scope.openFullscreenMap = function ($event) {\r\n $event && $event.stopPropagation();\r\n $scope.$emit('map.openFullscreenMap');\r\n }\r\n\r\n $scope.$on('$destroy', function () {\r\n //unbindFeedEventReceived();\r\n channelPttService && channelPttService.destroy();\r\n unbindChannelSelected();\r\n unbindUserPrivateTextEnabled();\r\n unbindSpeakersChangedEvent();\r\n unbindUserLeft();\r\n unbindUserJoined();\r\n unbindUsersLoaded();\r\n $log.debug('ChannelFeedController destroyed');\r\n })();\r\n\r\n init();\r\n }\r\n ])","angular\r\n .module('webcomm')\r\n .controller('MaxMapController', [\r\n '$scope',\r\n '$log',\r\n '$timeout',\r\n 'pttService',\r\n 'channelModel',\r\n 'endpointModel',\r\n 'muteService',\r\n function(\r\n $scope,\r\n $log,\r\n $timeout,\r\n pttService,\r\n channelModel,\r\n endpointModel,\r\n muteService) {\r\n var selectedChannel = channelModel.getSelectedChannel();\r\n var channelPttService = pttService.create(selectedChannel.id);\r\n\r\n $scope.$watch('selectedChannelId', function(newValue, oldValue) {\r\n channelPttService.destroy();\r\n channelPttService = pttService.create(newValue);\r\n });\r\n\r\n $scope.status = {\r\n isPTTButtonEnabled() {\r\n return channelPttService.canTransmitAudio();\r\n },\r\n isPttOn() {\r\n return channelPttService.isPttOn();\r\n },\r\n getPttIconName() {\r\n return channelPttService.getPttIconName(false);\r\n }\r\n }\r\n\r\n $scope.muteStatus = {\r\n muteIconName() {\r\n return this.isMuted() ? \"off\" : \"on\";\r\n },\r\n isMuted() {\r\n return muteService.getMuteStatus(selectedChannel.id);\r\n },\r\n toggleMute() {\r\n muteService.toggleMute(selectedChannel.id);\r\n }\r\n };\r\n\r\n $scope.pttStart = function() {\r\n channelPttService.pttStart();\r\n };\r\n\r\n $scope.pttStop = function() {\r\n channelPttService.pttStop();\r\n };\r\n\r\n $scope.closeFullscreenMap = function() {\r\n $scope.$emit('map.closeFullscreenMap');\r\n }\r\n\r\n var unbindEndpointsLoaded = $scope.$on('endpointModel.endpointsLoaded', function (e, channelEndpoints) {\r\n $scope.endpoints = channelEndpoints;\r\n });\r\n\r\n var unbindPresenceUpdated = $scope.$on('endpointModel.presenceUpdated', function (event, channelEndpoints) {\r\n $scope.endpoints = channelEndpoints;\r\n });\r\n\r\n $scope.$on('$destroy', function() {\r\n channelPttService && channelPttService.destroy();\r\n unbindEndpointsLoaded();\r\n unbindPresenceUpdated();\r\n $log.debug('maxMapController destroyed');\r\n });\r\n }\r\n ]);","angular\r\n .module('webcomm')\r\n .directive('privateCall', function () {\r\n return {\r\n restrict: 'E',\r\n scope: {},\r\n bindToController: {\r\n channel: '=',\r\n selectedChannelId: '=',\r\n created: '&onCreated',\r\n removed: '&onRemoved'\r\n },\r\n templateUrl: 'app/main/channel/privateCallChannel.html',\r\n controller: 'PrivateCallChannelController',\r\n controllerAs: 'pcc'\r\n };\r\n })\r\n .controller(\r\n 'PrivateCallChannelController', [\r\n '$scope',\r\n '$log',\r\n '$timeout',\r\n 'channelModel',\r\n 'privateCallPttService',\r\n 'privateCallService',\r\n function ($scope, $log, $timeout, channelModel, privateCallPttService, privateCallService) {\r\n var vm = this;\r\n this.$onInit = function () {\r\n var channelPttService = privateCallPttService.create(vm.channel.id);\r\n var activityMessageTimer;\r\n var _pttPending = false;\r\n\r\n function displayActivityMessaage(msg) {\r\n vm.status.activityMessage = msg;\r\n vm.status.isActivityMessageVisible = true;\r\n\r\n activityMessageTimer = $timeout(function () {\r\n vm.status.activityMessage = \"\";\r\n vm.status.isActivityMessageVisible = false;\r\n }, 5000);\r\n }\r\n\r\n function callRequest(pttPending) {\r\n privateCallService.callRequest(vm.channel.calleeNumber, vm.channel.participantId, vm.channel.calleeName, vm.channel.bargeCall)\r\n .then(() => {\r\n vm.status.activityMessage = \"\"; // Should probably be a call timer\r\n if (pttPending && vm.channel.bargeCall) {\r\n _pttPending = true;\r\n }\r\n })\r\n .catch((err) => {\r\n $log.error(err);\r\n vm.status.activityMessage = err;\r\n });\r\n }\r\n\r\n vm.created();\r\n\r\n vm.status = {\r\n isSelected: function () { return vm.selectedChannelId === vm.channel.id; },\r\n isPTTButtonEnabled() {\r\n return vm.channel.bargeCall || channelPttService.canTransmitAudio();\r\n },\r\n getPttIconName() {\r\n return channelPttService.getPttIconName(this.isSelected());\r\n },\r\n isPttOn() {\r\n return channelPttService.isPttOn();\r\n },\r\n activeCallExists: privateCallService.activeCallExists,\r\n callOfferFromUserExists: privateCallService.callOfferFromUserExists,\r\n isActivityMessageVisible: false,\r\n callEnded: false,\r\n callAnswered: vm.channel.callActive,\r\n isDialing: false\r\n }\r\n\r\n vm.hidePhoneIcon = () => {\r\n return this.status.isDialing ||\r\n this.status.callAnswered ||\r\n this.status.activeCallExists() ||\r\n this.status.callOfferFromUserExists(this.channel.participantId);\r\n };\r\n\r\n vm.closeChannel = function () {\r\n vm.channel.active = false;\r\n\r\n $scope.$emit('privateCallChannelClosed', vm.channel);\r\n };\r\n\r\n vm.pttStart = function ($event) {\r\n var pttState = vm.status.getPttIconName();\r\n $log.debug('private call pttStart', pttState);\r\n // this is to stop the system from interpreting the PTT click as a channel select\r\n if ($event) {\r\n $event.stopImmediatePropagation();\r\n }\r\n\r\n if (!channelPttService.isPttOn() && pttState !== 'disabled' && pttState !== 'requesting') {\r\n\r\n if (vm.channel.bargeCall && !vm.status.callAnswered && !vm.status.isDialing) {\r\n callRequest(true);\r\n } else {\r\n channelPttService.pttStart();\r\n }\r\n }\r\n };\r\n\r\n vm.pttStop = function ($event) {\r\n $log.debug('private call pttStop');\r\n // this is to stop the system from interpreting the PTT click as a channel select\r\n if ($event) {\r\n $event.stopImmediatePropagation();\r\n }\r\n\r\n if (channelPttService.isPttOn()) {\r\n channelPttService.pttStop();\r\n }\r\n };\r\n\r\n vm.phoneButtonClick = function ($event) {\r\n if ($event) {\r\n $event.stopImmediatePropagation();\r\n }\r\n\r\n if (!vm.status.callAnswered && !vm.status.isDialing) {\r\n callRequest();\r\n }\r\n else {\r\n privateCallService.callHangup(vm.channel.callId)\r\n .then(() => {\r\n if (vm.status.callAnswered) {\r\n vm.status.activityMessage = 'Call ended';\r\n }\r\n else {\r\n vm.status.activityMessage = 'Call cancelled';\r\n }\r\n\r\n vm.status.isDialing = false;\r\n vm.status.callAnswered = false;\r\n vm.status.isActivityMessageVisible = true;\r\n });\r\n }\r\n };\r\n\r\n vm.highlightSpeakingChannel = function (isHighlighted = true) {\r\n vm.status.talkingHighlightClass = isHighlighted ? \"talking5\" : \"\";\r\n };\r\n\r\n var unbindPrivateCallPTTOff = $scope.$on('privateCallService.callPttOff', (e, call) => {\r\n if (vm.channel.callId === call.callId) {\r\n channelPttService.callTooLong();\r\n }\r\n });\r\n\r\n var unbindPrivateCallProgress = $scope.$on('privateCallService.callProgressReceived', (e, data) => {\r\n if (vm.channel.callId === data.callId) {\r\n if (data.callState === 2) {\r\n vm.status.isActivityMessageVisible = false;\r\n vm.status.callAnswered = false;\r\n vm.status.isDialing = true;\r\n } else if (data.callState === 3) {\r\n if (_pttPending) {\r\n _pttPending = false;\r\n channelPttService.pttStart();\r\n }\r\n vm.status.isDialing = false;\r\n vm.status.callAnswered = true;\r\n vm.status.activityMessage = '';\r\n }\r\n }\r\n });\r\n\r\n var unbindPrivateCallHangup = $scope.$on('privateCallService.callHangupReceived', (e, data) => {\r\n if (data) {\r\n if (vm.channel.callId === data.callId) {\r\n vm.status.isDialing = false;\r\n if (vm.status.callAnswered) {\r\n vm.status.activityMessage = 'Call ended';\r\n }\r\n else {\r\n vm.status.activityMessage = 'No answer';\r\n }\r\n\r\n vm.status.callAnswered = false;\r\n vm.status.isActivityMessageVisible = true;\r\n }\r\n }\r\n });\r\n\r\n var unbindReconnecting = $scope.$on('isReconnecting', (e, reconnecting) => {\r\n if (reconnecting) {\r\n vm.status.isDialing = false;\r\n vm.status.callAnswered = false;\r\n }\r\n });\r\n\r\n $scope.$on(\r\n \"$destroy\",\r\n function (event) {\r\n vm.removed();\r\n unbindReconnecting();\r\n unbindPrivateCallProgress();\r\n unbindPrivateCallHangup();\r\n unbindPrivateCallPTTOff();\r\n if (activityMessageTimer) {\r\n $timeout.cancel(activityMessageTimer);\r\n }\r\n }\r\n );\r\n\r\n vm.select = function (channelId) {\r\n if (!vm.status.isSelected()) {\r\n vm.isMobileFeedVisible = true;\r\n channelModel.selectChannel(channelId);\r\n } else { // Barf, i hate this, but best I can do for now --scott s\r\n $scope.$parent.mobile.isMainMenuSelected = false;\r\n }\r\n };\r\n };\r\n }\r\n ]);\r\n","(function(angular) {\r\n\r\n function setVisibility(contact) {\r\n var callEl = angular.element(document.getElementById(`call-${contact.userName}`));\r\n var chatEl = angular.element(document.getElementById(`chat-${contact.userName}`));\r\n\r\n var togglePhone = (on) => {\r\n callEl.toggleClass('fa-phone', on);\r\n callEl.toggleClass('fa-fw', !on);\r\n };\r\n\r\n if (contact.isPresent && contact.canTxt) {\r\n chatEl.removeClass('ng-hide');\r\n } else {\r\n chatEl.addClass('ng-hide');\r\n }\r\n\r\n if (contact.callAlias && contact.canP2P) {\r\n if (!contact.disableP2P) {\r\n togglePhone(true);\r\n } else {\r\n togglePhone(false);\r\n }\r\n } else {\r\n togglePhone(false);\r\n }\r\n }\r\n\r\n angular\r\n .module('webcomm')\r\n .controller('ContactsController', [\r\n '$scope',\r\n '$log',\r\n '$timeout',\r\n 'contactService',\r\n 'userService',\r\n 'anchorInfoService',\r\n function ($scope, $log, $timeout, contactService, userService, anchorInfoService) {\r\n\r\n $log.debug('Loading ContactsController');\r\n\r\n var contactsNav = {};\r\n var contacts = {};\r\n var start = 'A'.charCodeAt(0);\r\n var end = start + 26;\r\n var selfCanP2P = true;\r\n $scope.pageSize = 100; \r\n $scope.aiService = anchorInfoService;\r\n $scope.contactService = contactService;\r\n $scope.visibleProvider = [];\r\n $scope.contactsByLetter = {};\r\n\r\n $scope.getNavKeys = function () {\r\n let a = []; \r\n for (let x = start; x < end; x++) {\r\n a.push(String.fromCharCode(x));\r\n }\r\n a.push('*'); //non-alphabet start char needs to be the last\r\n return a;\r\n }\r\n\r\n /* Replace this with a call to a language service, to get a language specific keys */\r\n var navKeys = $scope.getNavKeys();\r\n\r\n /* Initialize contacts object with an empty array for each key in navKeys array */\r\n navKeys.forEach((l) => {\r\n contactsNav[l] = [];\r\n });\r\n\r\n /* Get contacts into array based on row index */\r\n $scope.anchor = $scope.aiService.createAnchor();\r\n\r\n let currIndex = $scope.anchor.value - $scope.anchor.before;\r\n contactService.getContacts($scope.anchor)\r\n .then((result) => {\r\n let c = '';\r\n let currIndex = $scope.anchor.value;\r\n result.data.forEach((d) => {\r\n contacts[d.userName] = d;\r\n c = d.name.substr(0, 1);\r\n if (c.charCodeAt(0) >= 97 && c.charCodeAt(0) <= 122) {\r\n c = c.toUpperCase();\r\n }\r\n if (c.charCodeAt(0) >= 65 && c.charCodeAt(0) <= 90) {\r\n contactsNav[c].push(d);\r\n }\r\n else {\r\n contactsNav['*'].push(d);\r\n }\r\n currIndex++;\r\n });\r\n $scope.totalContacts = result.totalContacts;\r\n $scope.contactsByLetter = contactsNav;\r\n \r\n });\r\n\r\n // Will need to do a user service lookup to see the state of each user to determine if\r\n // Phone icon should be visible\r\n\r\n var unbindContactJoined = $scope.$on('contactService.contactUpdated', (e, endpoint) => {\r\n var contact = contacts[endpoint.userName.toLowerCase()];\r\n if(contact) {\r\n if (!contact.endpoints.has(endpoint.id)) {\r\n if (contact.endpoints.size === 0) {\r\n let unbindUserJoined = $scope.$on('userService.userJoined', (e, user) => {\r\n if (user.userName === endpoint.userName) {\r\n contact.canP2P = user.privateCallEnabled;\r\n\r\n $scope.$broadcast('contactController.contactJoined', contact);\r\n unbindUserJoined();\r\n }\r\n });\r\n }\r\n\r\n contact.isPresent = true;\r\n contact.endpoints.add(endpoint.id);\r\n } else {\r\n\r\n if (endpoint.disposition === 'Phone') {\r\n contact.canP2P = false;\r\n } else {\r\n contact.canTxt = endpoint.privateTxtEnabled ? true : false;\r\n contact.canP2P = true;\r\n for (let ep of contact.endpoints) {\r\n if (ep.disposition === 'Phone') {\r\n contact.canP2P = false;\r\n break;\r\n }\r\n }\r\n }\r\n\r\n if (selfCanP2P) {\r\n $scope.$broadcast('contactController.contactUpdated', contact);\r\n }\r\n }\r\n }\r\n });\r\n\r\n var unbindSelfUpdated = $scope.$on('contactService.selfUpdated', (e, endpoint) => {\r\n var contact;\r\n if(endpoint.disposition === 'Phone') {\r\n selfCanP2P = false;\r\n Object.getOwnPropertyNames(contacts).forEach((key) => {\r\n contact = contacts[key];\r\n if(contact.isPresent && contact.callAlias) {\r\n contact.disableP2P = true;\r\n\r\n $scope.$broadcast('contactController.contactUpdated', contact);\r\n }\r\n });\r\n } else if(!selfCanP2P) {\r\n selfCanP2P = true;\r\n Object.getOwnPropertyNames(contacts).forEach((key) => {\r\n contact = contacts[key];\r\n if(contact.isPresent && contact.callAlias) {\r\n delete contact.disableP2P;\r\n contact.canP2P = true;\r\n\r\n $scope.$broadcast('contactController.contactUpdated', contact);\r\n }\r\n });\r\n }\r\n });\r\n\r\n var unbindContactOffline = $scope.$on('contactService.contactOffline', (e, endpointId, userName) => {\r\n var contact = contacts[userName];\r\n\r\n if (contact.endpoints.size === 1) {\r\n contact.endpoints.clear();\r\n contact.isPresent = false;\r\n contact.canP2P = false;\r\n } else {\r\n contact.endpoints.delete(endpointId);\r\n }\r\n\r\n $scope.$broadcast('contactController.contactLeft', contact);\r\n });\r\n\r\n $scope.$on('destroy', function () {\r\n unbindContactJoined();\r\n unbindContactOffline();\r\n unbindSelfUpdated();\r\n });\r\n\r\n $scope.$emit('timeForResize');\r\n }\r\n ])\r\n .directive('contactList', ['$compile','$log', function ($compile, $log) {\r\n return {\r\n templateUrl: 'app/main/contacts/contacts.html',\r\n restrict: 'E',\r\n link: function (scope, element) {\r\n\r\n // add listener for scroll event\r\n let contactEntries = angular.element(element[0].querySelector('#contact-entries'))[0];\r\n\r\n // clear the view \r\n scope.clearView = function() {\r\n let contactsNav = {'*': []};\r\n scope.contactsByLetter = contactsNav;\r\n console.log(\" --- End of Clear View ----\");\r\n }\r\n\r\n // define scroll event handler\r\n scope.onScroll = function (evt) {\r\n\r\n if (scope.onPageFaultHandling === true) {\r\n console.log(\"ignores scroll event while page fault is processing\");\r\n return;\r\n }\r\n\r\n let target = evt.target; \r\n if (target.offsetHeight + target.scrollTop == target.scrollHeight) {\r\n // get a new page if page fault occurred. \r\n if (scope.anchor.value + scope.anchor.after < scope.totalContacts - 1) {\r\n console.log(\"Page fault detected at the bottom\");\r\n scope.viewportHeight = Math.floor(\r\n target.offsetHeight / target.scrollHeight * scope.pageSize);\r\n scope.anchor.value += (scope.pageSize - scope.viewportHeight); \r\n // Load a new page and rendered it on the UI\r\n console.log(\"Page fault at \" + scope.anchor.value + \", out of \" + scope.totalContacts);\r\n scope.clearView(); \r\n scope.handlePageFault(scope.anchor); // page fault at the bottom\r\n }\r\n\r\n console.log(\"Touched bottom of scrollbar\");\r\n } else if (target.scrollTop == 0) {\r\n $log.debug(\"touch scrollTop !\");\r\n \r\n if (scope.anchor.value > 0) {\r\n // Get a previous page \r\n let screenHeight = scope.viewportHeight | Math.floor(0.1 * scope.pageSize);\r\n console.log(\"Reduced by \" + screenHeight);\r\n scope.anchor.value -= screenHeight; \r\n if (scope.anchor.value < 0) {\r\n scope.anchor.value = 0;\r\n }\r\n console.log(\"Page fault at the scroll top :\" + scope.anchor.value);\r\n scope.clearView(); \r\n scope.handlePageFault(scope.anchor); // page fault at the top\r\n } else {\r\n console.log(\"There is no more page at the beginning !!\");\r\n }\r\n }\r\n };\r\n\r\n if (contactEntries) {\r\n contactEntries.addEventListener(\"scroll\", scope.onScroll);\r\n console.log(\"added scroll listener !!\")\r\n } else {\r\n console.log(\"Failed to find contactEntries \", element[0].innerHTML);\r\n }\r\n\r\n scope.scrollToView = function (key) {\r\n // Get a new page based on key\r\n // There is no way to search element from start_char as *\r\n\r\n let table = angular.element(element[0].querySelector('#contacts-table-' + (key == '*' ? 'special' : key)))[0];\r\n if (table) {\r\n table.scrollIntoView();\r\n } \r\n };\r\n\r\n scope.handlePageFault = function (anchor) {\r\n scope.onPageFaultHandling = true;\r\n scope.contactService.getContacts(anchor)\r\n .then((result) => {\r\n let c = '';\r\n let contactsNav = {};\r\n let contacts = {};\r\n /* Replace this with a call to a language service, to get a language specific keys */\r\n var navKeys = scope.getNavKeys();\r\n\r\n /* Initialize contacts object with an empty array for each key in navKeys array */\r\n navKeys.forEach((l) => {\r\n contactsNav[l] = [];\r\n });\r\n let currIndex = scope.anchor.value - scope.anchor.before;\r\n console.log(\" <---- result listing starting index = \", currIndex);\r\n for (let i = 0; i < 3 && i < result.data.length; i++) {\r\n console.log(\" first data :\" + result.data[i].userName + \", name= \"+ result.data[i].name + \", callAlias = \" + result.data[i].callAlias);\r\n }\r\n result.data.forEach((d) => {\r\n contacts[d.userName] = d;\r\n c = d.name.substr(0, 1);\r\n \r\n if (c.charCodeAt(0) >= 97 && c.charCodeAt(0) <= 122) {\r\n c = c.toUpperCase();\r\n }\r\n\r\n if (c.charCodeAt(0) >= 65 && c.charCodeAt(0) <= 90) {\r\n contactsNav[c].push(d);\r\n } else {\r\n contactsNav['*'].push(d);\r\n }\r\n currIndex++;\r\n });\r\n if (result.data.length > 0) {\r\n // clean the screen \r\n scope.contactsByLetter = contactsNav;\r\n console.log(\"Just updating contacts information after page fault handling\");\r\n }\r\n })\r\n .catch( (err) => {\r\n $log.debug(\"Exception at PageFault handling : \" + err);\r\n console.log(\"===> Exception caught : \"+ err +\" <===\");\r\n })\r\n .finally( () => {\r\n scope.onPageFaultHandling = false;\r\n });\r\n }\r\n\r\n var unbindContactJoined = scope.$on('contactController.contactJoined', (e, d) => {\r\n setVisibility(d);\r\n });\r\n\r\n var unbindContactLeft = scope.$on('contactController.contactLeft', (e, d) => {\r\n setVisibility(d);\r\n });\r\n\r\n var unbindContactDispositionChanged = scope.$on('contactController.contactUpdated', (e, d) => {\r\n setVisibility(d);\r\n });\r\n\r\n scope.$on('destroy', function (e) {\r\n unbindContactJoined();\r\n unbindContactLeft();\r\n unbindContactDispositionChanged();\r\n });\r\n },\r\n controller: 'ContactsController'\r\n };\r\n }])\r\n .controller('ContactListItemsController', [\r\n '$scope',\r\n '$log',\r\n '$timeout',\r\n 'contactService',\r\n 'privateCallService',\r\n 'endpointModel',\r\n 'channelModel',\r\n function ($scope, $log, $timeout, contactService, privateCallService, endpointModel, channelModel) {\r\n\r\n function isBargeCall(contact) {\r\n return contact.type === 'RADIO';\r\n }\r\n\r\n function makeCall(contact) {\r\n privateCallService.callRequest(contact.callAlias, contact.userName, contact.name, isBargeCall(contact))\r\n .then((resp) => {\r\n $scope.$emit('makingCall', resp);\r\n })\r\n .catch(err => $log.error(err));\r\n }\r\n\r\n function openPrivateTalkgroup(contact) {\r\n var myEndpoint = endpointModel.getMyEndpoint();\r\n channelModel.selectChannel(channelModel.addOrUpdatePrivateCallChannel(2, myEndpoint.userName,\r\n contact.userName, contact.callAlias, contact.name, null, contact.userName, isBargeCall(contact)));\r\n }\r\n\r\n var unbindContactAction = $scope.$on('contactAction', function (e, action, contact) {\r\n if (action === 'call' && !isBargeCall(contact)) {\r\n makeCall(contact);\r\n } else if (action === 'chat') {\r\n openPrivateTalkgroup(contact);\r\n } else if ( isBargeCall(contact)) {\r\n openPrivateTalkgroup(contact);\r\n $scope.$emit('makingCall');\r\n }\r\n });\r\n\r\n $scope.$on('destroy', function (e) {\r\n unbindContactAction();\r\n });\r\n }\r\n ])\r\n .directive('contactListItems', ['$templateRequest', '$compile', function ($templateRequest, $compile) {\r\n return {\r\n restrict: 'E',\r\n scope: {\r\n contacts: '='\r\n },\r\n replace: true,\r\n controller: 'ContactListItemsController',\r\n link: function (scope, element) {\r\n\r\n $templateRequest('app/main/contacts/contactItem.html').then((html) => {\r\n var template, nameEl, callEl, chatEl, buttons;\r\n scope.contacts.forEach((contact) => {\r\n template = angular.element(html);\r\n buttons = template.find('i');\r\n nameEl = angular.element(template.children()[0]);\r\n callEl = angular.element(buttons[0]);\r\n chatEl = angular.element(buttons[1]);\r\n nameEl.html(contact.name)\r\n callEl.attr('id', `call-${contact.userName}`);\r\n chatEl.attr('id', `chat-${contact.userName}`);\r\n buttons\r\n //.data('userName', contact.userName)\r\n //.data('classAlias', contact.callAlias)\r\n .data('contact', contact)\r\n .on('click', function () {\r\n let $this = angular.element(this);\r\n let action = $this.hasClass('call') ? 'call' : 'chat';\r\n //let user = $this.data('userName');\r\n //let number = $this.data('callAlias');\r\n if (action) {\r\n scope.$emit('contactAction', action, $this.data('contact'));\r\n }\r\n });\r\n\r\n element.append(template);\r\n setVisibility(contact);\r\n });\r\n });\r\n }\r\n };\r\n }]);\r\n})(angular);\r\n","angular.module('webcomm')\r\n .directive('notify', function() {\r\n return {\r\n restrict: 'E',\r\n transclude: true,\r\n scope: {\r\n 'close': '&onClose',\r\n 'mode': '='\r\n },\r\n templateUrl: 'app/main/notify/notify.html'\r\n };\r\n });","class ReconnectController {\r\n constructor($scope, $log, $location, $timeout, connectionService) {\r\n const RECONNECT_TIMEOUT_IN_MILLISECONDS = 600000; // 10 min\r\n\r\n this.timeoutPromise = null;\r\n this.$scope = $scope;\r\n this.$log = $log;\r\n this.$location = $location;\r\n this.connectionService = connectionService;\r\n this.isReconnecting = false;\r\n\r\n $scope.$on('isReconnecting', (event, isReconnecting) => {\r\n this.isReconnecting = isReconnecting;\r\n \r\n if(this.timeoutPromise) {\r\n $timeout.cancel(this.timeoutPromise);\r\n }\r\n\r\n if (isReconnecting) {\r\n this.timeoutPromise = $timeout(() => this.cancel(), RECONNECT_TIMEOUT_IN_MILLISECONDS);\r\n }\r\n });\r\n }\r\n\r\n cancel() {\r\n this.isReconnecting = false;\r\n this.connectionService.cancelReconnect();\r\n }\r\n}\r\n\r\nangular.module('webcomm')\r\n .directive('reconnect', function () {\r\n return {\r\n templateUrl: 'app/main/reconnect/reconnect.html',\r\n replace: true,\r\n controller: 'ReconnectController',\r\n controllerAs: 'reconnect'\r\n };\r\n })\r\n .controller('ReconnectController', ['$scope', '$log', '$location', '$timeout', 'connectionService', ReconnectController]);\r\n","angular\r\n .module('webcomm')\r\n .controller('SettingsController', [\r\n '$rootScope',\r\n '$scope',\r\n '$log',\r\n 'wtcpjsService',\r\n 'settingsService',\r\n 'channelModel',\r\n 'profileModel',\r\n 'audioService',\r\n function ($rootScope, $scope, $log, wtcpjsService, settingsService, channelModel, profileModel, audioService) {\r\n\r\n var selectedProfile = profileModel.getSelectedProfile();\r\n var channels = {};\r\n var initialVolume = $scope.volume = settingsService.getVolume();\r\n var channelIds = profileModel.getChannelIdsForProfile(selectedProfile.profileId);\r\n\r\n $scope.locationToggleOn = false;\r\n $scope.locationToggleDisabled = true;\r\n $scope.webcommVersion = window.webcomm_version;\r\n $scope.talkGroup = {\r\n showMaxMessage: channelIds.length > wtcpjsService.getMaxActiveChannelCount(),\r\n maxActiveChannels: wtcpjsService.getMaxActiveChannelCount(),\r\n selection: [],\r\n numSelected() { return this.selection.filter(s => s.active).length; },\r\n isSelectionValid() { return this.numSelected() <= this.maxActiveChannels;}\r\n };\r\n\r\n var copyChannels = () => {\r\n channelIds = profileModel.getChannelIdsForProfile(selectedProfile.profileId);\r\n angular.forEach(channelIds, (v, k) => {\r\n channels[v] = channelModel.getChannel(v);\r\n \r\n $scope.talkGroup.selection.push({\r\n 'name': channels[v].name,\r\n 'active': channels[v].active,\r\n 'id': channels[v].id\r\n });\r\n });\r\n };\r\n\r\n copyChannels();\r\n\r\n $scope.toggleLocation = function() {\r\n if ($scope.locationToggleDisabled === false) {\r\n $scope.locationToggleOn ? $scope.locationToggleOn = false : $scope.locationToggleOn = true;\r\n }\r\n };\r\n\r\n $scope.enableToggle = function() {\r\n $scope.locationToggleDisabled = false;\r\n $scope.locationToggleOn = settingsService.shareLocation;\r\n };\r\n\r\n $scope.disableToggle = function() {\r\n $scope.locationToggleDisabled = true;\r\n $scope.locationToggleOn = false;\r\n };\r\n\r\n $scope.saveSettings = () => {\r\n let channelsChanged = false;\r\n for (let c of $scope.talkGroup.selection) {\r\n if (channels[c.id].active !== c.active) {\r\n channels[c.id].active = c.active;\r\n channelsChanged = true;\r\n }\r\n }\r\n\r\n settingsService.persistVolume($scope.volume);\r\n initialVolume = $scope.volume; // so we don't revert on 'closeSettings'\r\n settingsService.updateChannelSelection(channels);\r\n settingsService.shareLocation = $scope.locationToggleOn;\r\n if (channelsChanged) {\r\n wtcpjsService.changeActiveChannels();\r\n channelModel.selectFirstActiveChannel();\r\n }\r\n $scope.closeSettings();\r\n };\r\n\r\n $scope.closeSettings = function() {\r\n copyChannels();\r\n $scope.volume = initialVolume;\r\n audioService.adjustVolume($scope.volume);\r\n $scope.$emit(\"settings.close\");\r\n };\r\n\r\n var unbindSlideEnded = $scope.$on(\"slideEnded\", function() {\r\n audioService.adjustVolume($scope.volume);\r\n });\r\n\r\n $scope.enableToggle();\r\n\r\n $scope.$on(\"$destroy\", function() {\r\n unbindSlideEnded();\r\n });\r\n }\r\n ]);","angular.module('webcomm').controller('CallEventController', ['$scope', '$log', 'timeFormattingService', function ($scope, $log, timeFormattingService) {\r\n $scope.timeSent = timeFormattingService.formatFeedDate($scope.feedEvent.clientTime);\r\n}]);","angular.module('webcomm').controller('EndpointStatusChangedController', ['$scope', '$log', 'timeFormattingService', function ($scope, $log, timeFormattingService) {\r\n $scope.timeSent = timeFormattingService.formatFeedDate($scope.feedEvent.clientTime);\r\n\r\n $scope.$evalAsync(() => {\r\n $scope.$emit('timeForResize');\r\n });\r\n}]);","angular.module('webcomm').controller('SpeakingEventController',\r\n ['$scope', '$log', '$interval', '$timeout', 'timeFormattingService', function ($scope, $log, $interval, $timeout, timeFormattingService) {\r\n let endpointId = $scope.feedEvent.data.endpointId;\r\n let startedSpeaking = $scope.feedEvent.data.startedSpeaking;\r\n let finishedSpeaking = $scope.feedEvent.data.finishedSpeaking;\r\n\r\n $scope.timeSent = timeFormattingService.formatFeedDate($scope.feedEvent.clientTime);\r\n $scope.leftOrRight = $scope.feedEvent.data.self ? \"right\" : \"left\";\r\n\r\n let timer;\r\n if (finishedSpeaking) {\r\n destroyScopes(); // no further updates - delete watchers\r\n $scope.duration = getDuration(startedSpeaking, finishedSpeaking);\r\n } else {\r\n $scope.duration = getDuration(startedSpeaking, new Date());\r\n timer = startTimer();\r\n }\r\n\r\n function getDuration(startedSpeaking, finishedSpeaking) {\r\n return Math.floor((finishedSpeaking.getTime() - startedSpeaking.getTime()) / (1000));\r\n }\r\n\r\n function startTimer() {\r\n return $interval(tick, 1000);\r\n function tick() {\r\n $scope.duration = getDuration(startedSpeaking, new Date());\r\n }\r\n }\r\n\r\n function stopTimer() {\r\n if (timer) {\r\n $interval.cancel(timer);\r\n }\r\n }\r\n\r\n // destroy scopes and watchers.\r\n function destroyScopes() {\r\n $timeout(function() {\r\n $scope.$parent.$parent.$destroy();\r\n }, 0);\r\n }\r\n\r\n var unbindFeedEventReceived = $scope.$on('feedModel.feedEventReceived', function (event, data) {\r\n if (data.type === \"end-speaking\" && data.data.endpointId === endpointId) {\r\n stopTimer();\r\n destroyScopes();\r\n }\r\n });\r\n\r\n $scope.$on('$destroy', function () {\r\n unbindFeedEventReceived();\r\n stopTimer();\r\n });\r\n }]);","angular.module('webcomm').controller('TextMessageEventController', ['$scope', '$log', '$timeout', 'timeFormattingService', function ($scope, $log, $timeout, timeFormattingService) {\r\n $scope.leftOrRight = $scope.feedEvent.data.Self ? \"right\" : \"left\";\r\n $scope.stretchOrFixed = $scope.feedEvent.data.message.length < 60 ? \"stretch\" : \"fixed\";\r\n $scope.retry = false;\r\n $scope.messageStatus = $scope.feedEvent.confirmed ? \"sent\" : \"sending\";\r\n $scope.feedMessage = htmlEncode($scope.feedEvent.data.message);\r\n $scope.important = $scope.feedEvent.data.important ? \"text-alert\" : \"\";\r\n \r\n var unbindIsReconnecting;\r\n\r\n // delete the watchers if we're re-loading this channel\r\n if ($scope.feedEvent.confirmed) {\r\n destroyScopes();\r\n }\r\n\r\n if(typeof $scope.feedEvent.clientTime === 'object') {\r\n $scope.timeSent = timeFormattingService.formatFeedDate($scope.feedEvent.clientTime);\r\n }\r\n else {\r\n $scope.timeSent = $scope.feedEvent.clientTime;\r\n $scope.errorMessage = $scope.feedEvent.errorMessage;\r\n\r\n unbindIsReconnecting = $scope.$on('isReconnecting', function(event, data) {\r\n if (!data) {\r\n $scope.retry = true;\r\n }\r\n });\r\n }\r\n\r\n var unbindTextMessageSentError = $scope.$on('textMessageSentError', function(event, feedId, err) {\r\n if ($scope.feedEvent.feedId === feedId) {\r\n $scope.messageStatus = \"error\";\r\n $scope.errorMessage = $scope.feedEvent.errorMessage = err;\r\n $scope.feedEvent.confirmed = true;\r\n $scope.timeSent = $scope.feedEvent.clientTime = \"error\";\r\n destroyScopes();\r\n }\r\n });\r\n\r\n var unbindTextMessageSentConfirmed = $scope.$on('textMessageSentConfirmed', function(event, feedId) {\r\n if ($scope.feedEvent.feedId === feedId) {\r\n $scope.messageStatus = \"sent\";\r\n $scope.feedEvent.confirmed = true;\r\n $scope.timeSent = timeFormattingService.formatFeedDate($scope.feedEvent.clientTime);\r\n destroyScopes();\r\n }\r\n });\r\n\r\n var unbindTextFeedFinished = $scope.$on('textMessageService.textMessageComplete', function(e, feedId) {\r\n $scope.feedEvent.confirmed = true;\r\n destroyScopes();\r\n });\r\n\r\n function destroyScopes() {\r\n $timeout(function () {\r\n $scope.$parent.$parent.$destroy();\r\n }, 0);\r\n }\r\n\r\n $scope.$on('destroy', function() {\r\n if(unbindIsReconnecting) {\r\n unbindIsReconnecting();\r\n }\r\n \r\n unbindTextMessageSentConfirmed();\r\n unbindTextMessageSentError();\r\n unbindTextFeedFinished();\r\n \r\n $log.debug('text message event scope destroyed');\r\n });\r\n}]);","class EndpointMapController {\r\n constructor($log, $scope, $rootScope, $timeout, $interval, NgMap, endpointModel, locationService, channelModel, userService, privateCallService) {\r\n this.scope = $scope;\r\n if (!$scope.elementId)\r\n throw new Error(\"must provide 'elementId' scope param - it will used as the html element id for the ng-map component\");\r\n this.elementId = $scope.elementId;\r\n this.map = undefined; // initialized in 'init'\r\n this.mapRightclickListener = null;\r\n\r\n this.log = $log;\r\n this.timeout = $timeout;\r\n this.interval = $interval;\r\n this.NgMap = NgMap;\r\n this.locationService = locationService;\r\n this.privateCallService = privateCallService;\r\n this.endpointModel = endpointModel;\r\n this.myEndpoint = endpointModel.getMyEndpoint();\r\n this.channelModel = channelModel;\r\n this.userService = userService;\r\n\r\n this.endpoints = this.scope.endpoints = endpointModel.getChannelEndpoints(this.channelId);\r\n this.centerOn = \"[ 41.850033, -87.6500523 ]\"; // Default center of United States\r\n this.zoom = 3;\r\n\r\n var mapDisabled = false;\r\n\r\n var unbindEndpointsLoaded = $scope.$on('endpointModel.endpointsLoaded', (e, channelEndpoints) => {\r\n this.endpoints = this.scope.endpoints = channelEndpoints;\r\n //this.log.log(\"endpoints updated on \" + this.elementId, this.endpoints);\r\n });\r\n\r\n var unbindSharingLocation = $scope.$on('locationService.sharingLocation', (e, endpoint) => {\r\n this.centerMapView();\r\n });\r\n\r\n var unbindLocationCentered = $rootScope.$on('presenceTableController.locationPinClicked', (e, location) => {\r\n this.centerZoomMapOnLoc(location);\r\n });\r\n\r\n var unbindEndpointsDisabledOnChannel = $rootScope.$on('endpointModel.endpointsDisabledOnChannel', (e, channelId) => {\r\n mapDisabled = true;\r\n });\r\n\r\n var unbindEndpointsEnabledOnChannel = $rootScope.$on('endpointModel.endpointsEnabledOnChannel', (e, channelId) => {\r\n if(mapDisabled) {\r\n this.init(this.elementId);\r\n mapDisabled = false;\r\n }\r\n });\r\n\r\n $scope.$on('$destroy', () => {\r\n unbindEndpointsEnabledOnChannel();\r\n unbindEndpointsDisabledOnChannel();\r\n unbindEndpointsLoaded();\r\n unbindSharingLocation();\r\n unbindLocationCentered();\r\n if(this.mapRightclickListener) {\r\n this.mapRightclickListener.remove();\r\n }\r\n\r\n this.log.debug(this.elementId + ' EndpointMapController destroyed');\r\n });\r\n\r\n this.init(this.elementId);\r\n }\r\n\r\n init(id) {\r\n this.enableConfirm = true;\r\n this.NgMap.getMap({ id: id }).then((evtMap) => {\r\n this.map = evtMap;\r\n\r\n // not going to lie - i don't know why this sequence of events is needed, but it works and seems to be required.\r\n google.maps.event.trigger(this.map, 'resize');\r\n this.scope.$emit('timeForResize');\r\n this.timeout(() => {\r\n window.dispatchEvent(new Event('resize'));\r\n this.initializeMap();\r\n }, 50);\r\n\r\n }).catch((err) => {\r\n this.log.error(id + ': Error getting map', err);\r\n });\r\n }\r\n\r\n initializeMap() {\r\n var self = this;\r\n this.log.debug(this.elementId + ' map initialized, resizing');\r\n this.map.customMarkers.confirm.setVisible(false);\r\n\r\n // Set up right-click menu to set location\r\n if (!this.mapRightclickListener) {\r\n this.mapRightclickListener = google.maps.event.addListener(this.map, 'rightclick', (e) => {\r\n if (self.locationService.isSharingEnabled) {\r\n self.setLocationValue = e.latLng;\r\n self.map.customMarkers.confirm.setVisible(true);\r\n self.map.customMarkers.confirm.setPosition(e.latLng);\r\n }\r\n });\r\n }\r\n\r\n this.centerMapView();\r\n }\r\n\r\n centerMapView() {\r\n if (!this.locationService.isSharingEnabled) {\r\n this.fitAllEndpointsToBounds();\r\n } else {\r\n this.initiallyCenterOnSelfIfSharingLocation();\r\n }\r\n }\r\n\r\n fitAllEndpointsToBounds() {\r\n let endpoints = this.endpoints;\r\n if (endpoints.length === 0)\r\n this.log.warn('no endpoints to fit bounds');\r\n\r\n let latLngBounds = new google.maps.LatLngBounds();\r\n let latLng;\r\n endpoints.forEach(endpoint => {\r\n if (endpoint.location) {\r\n latLng = new google.maps.LatLng(endpoint.location.la, endpoint.location.lo);\r\n latLngBounds.extend(latLng);\r\n this.log.debug(\"added endpoint to bounds: \", endpoint.location.la, endpoint.location.lo);\r\n }\r\n });\r\n\r\n var center = latLngBounds.getCenter();\r\n if (center.lat() > 0) {\r\n this.log.debug(`setting $scope.centerOn to location: ${center.lat()}, ${center.lng()} ${typeof center.lat()}`);\r\n this.centerOn = `[ ${center.lat()}, ${center.lng()} ]`;\r\n this.map.fitBounds(latLngBounds);\r\n } else {\r\n this.log.warn(\"can't re-center for some reason - check the endpoints being added to the bounds.\");\r\n }\r\n }\r\n\r\n initiallyCenterOnSelfIfSharingLocation(ep) {\r\n var endpoint = ep || this.myEndpoint; //endpointModel.getMyEndpoint();\r\n if (endpoint.location) {\r\n this.centerZoomMapOnLoc(endpoint.location);\r\n } else {\r\n this.log.warn('attempted to initialize map centered on self, but endpoint had no location value');\r\n }\r\n }\r\n\r\n centerZoomMapOnLoc(loc) {\r\n if (loc && this.map) {\r\n this.log.debug(`moving map center to location: ${loc.la}, ${loc.lo} ${typeof loc.la}`);\r\n this.map.setCenter({lat: parseFloat(loc.la), lng: parseFloat(loc.lo)});\r\n this.map.setZoom(13);\r\n }\r\n }\r\n\r\n showDetail(ep) {\r\n if (ep !== this.myEndpoint) {\r\n this.selectedEndpoint = ep;\r\n this.map.showInfoWindow('endpoint-info', ep.id);\r\n }\r\n }\r\n\r\n sameUser() {\r\n return this.selectedEndpoint.userName === this.myEndpoint.userName;\r\n }\r\n\r\n getFlags(channelId) {\r\n return this.selectedEndpoint.flags.get(channelId);\r\n }\r\n\r\n showPhoneIcon(channelId) {\r\n let flags = this.getFlags(channelId);\r\n let isSelf = flags && flags.Self;\r\n let onPhone = this.selectedEndpoint.disposition === 'Phone';\r\n let sameUser = this.sameUser();\r\n return !isSelf && !onPhone && !sameUser && this.myEndpoint.callAlias;\r\n }\r\n\r\n showChatIcon(channelId) {\r\n if(channelId <= 0) { // No point showing this if the endpoint is already in a private talkgroup\r\n return false;\r\n }\r\n\r\n let flags = this.getFlags(channelId);\r\n let isSelf = flags && flags.Self;\r\n let canChat = this.selectedEndpoint.privateTxtEnabled;\r\n let sameUser = this.sameUser();\r\n return !isSelf && !sameUser && canChat;\r\n }\r\n\r\n hideDetail() {\r\n this.map && this.map.hideInfoWindow('endpoint-info');\r\n }\r\n\r\n closeMaximizedMap() {\r\n this.hideDetail();\r\n this.scope.$emit('map.closeFullscreenMap');\r\n }\r\n\r\n get channelId() {\r\n var _selectedChannel = this.channelModel.getSelectedChannel();\r\n return _selectedChannel ? _selectedChannel.id : void 0;\r\n }\r\n\r\n okShareLocation() {\r\n this.locationService.setLocation(this.setLocationValue.lat(), this.setLocationValue.lng());\r\n this.map.customMarkers.confirm.setVisible(false);\r\n }\r\n\r\n cancelShareLocation() {\r\n this.map.customMarkers.confirm.setVisible(false);\r\n }\r\n\r\n openPrivateTalkgroup(endpoint, call) {\r\n var user = this.userService.getUser(endpoint.userName);\r\n this.channelModel.addOrUpdateAndSelectPrivateCallChannel(this.userService.getUser(this.myEndpoint.userName), user);\r\n\r\n if (call)\r\n this.callEndpoint(user);\r\n else\r\n this.closeMaximizedMap();\r\n }\r\n\r\n callEndpoint(user) {\r\n this.closeMaximizedMap();\r\n this.privateCallService\r\n .callRequest(user.callAlias, user.userName, user.name)\r\n .then((resp) => this.scope.$emit('makingCall', resp))\r\n .catch(err => this.log.error(err));\r\n }\r\n}\r\n\r\nangular.module('webcomm')\r\n .directive('endpointMap', ['$log', function($log) {\r\n return {\r\n restrict: 'EA',\r\n scope: {\r\n elementId: '@'\r\n },\r\n templateUrl: 'app/main/channel/map/endpointMap.html',\r\n replace: true,\r\n controller: 'endpointMapController',\r\n controllerAs: 'mapController'\r\n };\r\n }])\r\n .controller('endpointMapController', [\r\n '$log',\r\n '$scope',\r\n '$rootScope',\r\n '$timeout',\r\n '$interval',\r\n 'NgMap',\r\n 'endpointModel',\r\n 'locationService',\r\n 'channelModel',\r\n 'userService',\r\n 'privateCallService',\r\n EndpointMapController]);","angular.module('webcomm')\r\n .directive('presenceTable', function () {\r\n return {\r\n templateUrl: 'app/main/channel/presence/presenceTable.html',\r\n replace: true,\r\n controller: 'PresenceTableController'\r\n };\r\n })\r\n .controller('PresenceTableController', [\r\n '$log',\r\n '$scope',\r\n 'userService',\r\n 'channelModel',\r\n 'privateCallService',\r\n 'endpointModel',\r\n function ($log, $scope, userService, channelModel, privateCallService, endpointModel) {\r\n\r\n var _myUserInfo;\r\n\r\n function reloadUsers(users) {\r\n $scope.users = users || userService.getUsers();\r\n\r\n _myUserInfo = userService.getUser(endpointModel.getMyEndpoint().userName);\r\n }\r\n\r\n $scope.publicTalkgroup = channelModel.getSelectedChannel() ? channelModel.getSelectedChannel().id >= 0 : true;\r\n\r\n $scope.showCallButton = (user) => {\r\n\r\n return user.privateCallEnabled &&\r\n !privateCallService.activeCallExists() &&\r\n _myUserInfo &&\r\n _myUserInfo.callAlias &&\r\n _myUserInfo.disposition !== 'phone';\r\n };\r\n\r\n $scope.presenceTableLocationClick = (user) => {\r\n $scope.$emit('presenceTableController.locationPinClicked', user.location);\r\n\r\n if(!user.self) {\r\n user.getNextLocation();\r\n }\r\n };\r\n\r\n $scope.openPrivateTalkgroup = (user, call) => {\r\n channelModel.addOrUpdateAndSelectPrivateCallChannel(_myUserInfo, user);\r\n\r\n if (call) {\r\n $scope.callEndpoint(user);\r\n }\r\n else {\r\n $scope.$emit('map.closeFullscreenMap');\r\n }\r\n };\r\n\r\n $scope.callEndpoint = (user) => {\r\n $scope.$emit('map.closeFullscreenMap');\r\n\r\n privateCallService\r\n .callRequest(user.callAlias, user.userName, user.displayName)\r\n .then((resp) => $scope.$emit('makingCall', resp))\r\n .catch(err => $log.error(err));\r\n }\r\n\r\n var unbindUserJoined = $scope.$on('userService.userJoined', (event, user) => {\r\n reloadUsers();\r\n });\r\n\r\n var unbindUserLeft = $scope.$on('userService.userLeft', (event, user) => {\r\n reloadUsers();\r\n });\r\n\r\n var unbindPresenceUpdated = $scope.$on('userService.userUpdated', (event, user) => {\r\n // this seems to be a good spot to trigger panel resizing - its the only on that seems to work for FF\r\n // this means it gets resized every time an endpoint gets added/changes :(\r\n // TODO: find a better place,\r\n $scope.$evalAsync(() => {\r\n $scope.$emit('timeForResize');\r\n });\r\n\r\n reloadUsers();\r\n });\r\n\r\n var unbindUsersLoaded = $scope.$on('userService.usersLoaded', (event, users) => {\r\n reloadUsers(users);\r\n });\r\n\r\n var unbindChannelSelected = $scope.$on('channelModel.channelSelected', (e, channel) => {\r\n $scope.publicTalkgroup = channel.id < 0 ? false : true;\r\n $scope.users.length = 0;\r\n });\r\n\r\n $scope.$on('$destroy', function () {\r\n unbindPresenceUpdated();\r\n unbindUserJoined();\r\n unbindUserLeft();\r\n unbindUsersLoaded();\r\n unbindChannelSelected();\r\n $log.debug('PresenceTableController destroyed');\r\n });\r\n\r\n reloadUsers();\r\n }]);\r\n ","angular\r\n .module('webcomm')\r\n .controller('MainController', [\r\n '$scope', \r\n '$log', \r\n '$location', \r\n '$filter', \r\n '$timeout',\r\n '$window',\r\n 'channelModel', \r\n 'connectionService', \r\n 'muteService',\r\n 'profileModel',\r\n 'privateCallService',\r\n 'endpointModel',\r\n 'authService',\r\n 'connectionHealthService',\r\n 'mapLoaderService',\r\n 'dispositionService',\r\n function($scope,\r\n $log,\r\n $location,\r\n $filter,\r\n $timeout,\r\n $window,\r\n channelModel,\r\n connectionService,\r\n muteService,\r\n profileModel,\r\n privateCallService,\r\n endpointModel,\r\n authService,\r\n connectionHealthService,\r\n mapLoaderService,\r\n dispositionService) {\r\n var selectedProfile;\r\n $scope.privateCallChannels = {};\r\n $scope.publicChannels = {};\r\n $scope.numPrivateCalls = 0;\r\n $scope.connectionInfo = {latency: 0, serverLag: 0}\r\n\r\n // notifications\r\n $scope.noMicrophoneNotification = $scope.noMicrophone;\r\n $scope.noMapKeyNotification = !mapLoaderService.mapKey;\r\n\r\n $scope.hideNotification = (prop) => { $scope[prop] = false; };\r\n\r\n function addChannelToModel(channelId) {\r\n let channel = channelModel.getChannel(channelId);\r\n $scope.channels[channelId] = channel;\r\n $scope.publicChannels[channelId] = channel;\r\n }\r\n\r\n var viewModeBeforeReconnect = null;\r\n\r\n var init = function() {\r\n $scope.channels = Object.assign({}, $scope.privateCallChannels);\r\n\r\n // take to login page if not logged in\r\n if (!connectionService.getCurrentUser()) {\r\n $scope.logOut();\r\n return;\r\n }\r\n\r\n selectedProfile = profileModel.getSelectedProfile();\r\n profileModel.getChannelIdsForProfile(selectedProfile.profileId).forEach(channelId => addChannelToModel(channelId));\r\n\r\n $scope.profileMenu.selectedProfileId = selectedProfile.profileId;\r\n $scope.profileMenu.selectedProfileName = selectedProfile.profileName;\r\n\r\n $log.info('MainController initialized');\r\n };\r\n\r\n function getMyUserName() {\r\n var unbindEndpointsUpdated = $scope.$on('endpointModel.presenceUpdated', function(event, data) {\r\n if (endpointModel.getMyEndpoint()) {\r\n $scope.userName = endpointModel.getMyEndpoint().name;\r\n unbindEndpointsUpdated();\r\n }\r\n });\r\n }\r\n\r\n $scope.inboundCall = false;\r\n $scope.showSettings = false;\r\n $scope.showFullMap = false;\r\n $scope.showStatusSelector = true;\r\n $scope.viewMode = 'talk-groups';\r\n $scope.mobile = {\r\n isMainMenuSelected: true\r\n }\r\n\r\n $scope.areChannelsAvailable = () => Object.keys($scope.channels).length > 0;\r\n $scope.areAnyChannelsActive = () => channelModel.areAnyChannelsActive();\r\n\r\n $scope.logOut = function() {\r\n $location.path(authService.loginPath);\r\n connectionService.logout();\r\n $log.debug(\"mainController.logOut\");\r\n };\r\n\r\n $scope.setViewMode = (mode) => {\r\n $scope.viewMode = mode;\r\n };\r\n\r\n $scope.profileMenu = {\r\n visible: false,\r\n confirmProfileChange: false,\r\n selectedProfile: '',\r\n profiles: profileModel.getProfiles(),\r\n hasMultipleProfiles: Object.keys(profileModel.getProfiles()).length > 1,\r\n toggle($event) {\r\n this.visible = !this.visible;\r\n }\r\n };\r\n\r\n $scope.openProfileSelect = function() {\r\n $scope.profileMenu.confirmProfileChange = true;\r\n $scope.profileMenu.visible = false;\r\n };\r\n\r\n $scope.changeProfile = function() {\r\n $scope.profileMenu.confirmProfileChange = false;\r\n if ($scope.profileMenu.selectedProfileId !== selectedProfile.profileId) {\r\n $scope.profileMenu.selectedProfileName = selectedProfile.profileName;\r\n connectionService.reconnect($scope.profileMenu.selectedProfileId);\r\n }\r\n //Reconnect here\r\n };\r\n\r\n $scope.openSettings = function() {\r\n $scope.showSettings = !$scope.showSettings;\r\n $scope.profileMenu.visible = false;\r\n }\r\n\r\n $scope.mute = {\r\n isMuted() {\r\n return muteService.allChannelsMuted();\r\n },\r\n toggleMute() {\r\n muteService.allChannelsMuted() ? muteService.unmuteAll() : muteService.muteAll();\r\n }\r\n };\r\n\r\n $scope.privateCallCreated = function() {\r\n $scope.numPrivateCalls++;\r\n };\r\n\r\n $scope.privateCallRemoved = function() {\r\n $scope.numPrivateCalls--;\r\n };\r\n\r\n $scope.callOffer = {\r\n callInfo: null,\r\n answering: false,\r\n answer() {\r\n this.answering = true;\r\n $log.info('answering call', this.callInfo);\r\n privateCallService.callAnswer()\r\n .then((call) => {\r\n $scope.inboundCall = false;\r\n this.answering = false; // reset state since the call was answered\r\n });\r\n },\r\n close() {\r\n if(!this.answering) {\r\n this.hangup();\r\n }\r\n },\r\n hangup() {\r\n $log.info('hangup call', this.callInfo);\r\n this.answering = false;\r\n privateCallService.callHangup(this.callInfo.callId)\r\n .then(() => {\r\n $scope.inboundCall = false;\r\n })\r\n .catch((err) => {\r\n $log.error(err);\r\n });\r\n }\r\n };\r\n\r\n // User status dropdown\r\n\r\n $scope.status = {\r\n isOpen: false,\r\n selected: 'ready',\r\n set: function(newStatus) {\r\n // This needs to use $q\r\n dispositionService.setDisposition(endpointModel.getMyEndpoint().id, newStatus);\r\n }\r\n };\r\n\r\n $scope.toggled = function(open) {\r\n $log.log('Dropdown is now: ', open);\r\n\r\n if(!open){\r\n $scope.profileMenu.toggle();\r\n }\r\n };\r\n\r\n $scope.toggleDropdown = function($event) {\r\n $event.preventDefault();\r\n $event.stopPropagation();\r\n $scope.status.isOpen = !$scope.status.isOpen;\r\n };\r\n\r\n // Map\r\n\r\n $scope.googleMapsLoaded = function() {\r\n let isLoaded = $window['google'];\r\n //$log.debug(\"isLoaded: \", isLoaded);\r\n return isLoaded;\r\n }\r\n\r\n getMyUserName();\r\n\r\n var unbindProfileNameChanged = $scope.$on('wtcpjsService.profileNameChanged', function(event, profileName) {\r\n $scope.profileMenu.selectedProfileName = profileName;\r\n });\r\n\r\n var unbindReconnecting = $scope.$on('isReconnecting', (e, reconnecting, tryAgain) => {\r\n if(reconnecting) {\r\n getMyUserName();\r\n viewModeBeforeReconnect = $scope.viewMode;\r\n if(viewModeBeforeReconnect === 'contacts') {\r\n $scope.viewMode = 'none';\r\n }\r\n } else {\r\n $scope.viewMode = viewModeBeforeReconnect;\r\n }\r\n })\r\n\r\n var unbindChannelSelected = $scope.$on('channelModel.channelSelected', function(event, channel) {\r\n $scope.selectedChannelId = channel.id;\r\n $scope.selectedChannelName = $scope.channels[channel.id].name;\r\n $scope.mobile.isMainMenuSelected = false;\r\n $log.debug(`mainController: new channel selected - ${channel.id}`);\r\n });\r\n\r\n var unbindChannelPropertiesRecieved = $scope.$on('wtcpjsService.channelPropertiesReceived', function(event, channel) {\r\n $scope.channels[channel.id] = channel;\r\n\r\n if($scope.selectedChannelId && $scope.selectedChannelId === channel.id) {\r\n $scope.selectedChannelName = $scope.channels[$scope.selectedChannelId].name;\r\n }\r\n });\r\n\r\n var unbindChannelRemoved = $scope.$on('channelModel.channelRemoved', function (event, channelId) {\r\n delete $scope.channels[channelId];\r\n //// if the deleted channel was selected - select the first channel\r\n //if ($scope.channels.keys > channelId === $scope.selectedChannelId)\r\n // channelModel.selectChannel($scope.channels[$scope.channels.keys()[0]].id);\r\n });\r\n\r\n var unbindPrivateCallChannelsCleared = $scope.$on('channelModel.privateCallChannelsCleared', function () {\r\n $scope.privateCallChannels = {};\r\n });\r\n\r\n var unbindChannelsUpdated = $scope.$on('channelModel.channelsCleared', function() {\r\n $log.info('channelModel.channelsCleared received in mainController');\r\n\r\n $scope.publicChannels = {};\r\n init();\r\n });\r\n\r\n var unbindActiveChannelsChanged = $scope.$on('wtcpjsService.activeChannelsChanged', function(event, channels) {\r\n $log.info('wtcpjsService.activeChannelsChanged received in mainController - ', channels);\r\n init();\r\n });\r\n\r\n var unbindPrivateCallChannelAdded = $scope.$on('channelModel.privateCallChannelAdded', function(event, channel) {\r\n $scope.channels[channel.id] = $scope.privateCallChannels[channel.id] = channel;\r\n });\r\n\r\n var unbindSettingsClose = $scope.$on('settings.close', function(event) {\r\n $scope.showSettings = false;\r\n event.preventDefault();\r\n });\r\n\r\n var unbindOpenFullscrenMap = $scope.$on('map.openFullscreenMap', function(event) {\r\n $scope.showFullMap = true;\r\n });\r\n\r\n var unbindCloseFullscreenMap = $scope.$on('map.closeFullscreenMap', function(event) {\r\n $scope.showFullMap = false;\r\n });\r\n\r\n var unbindConnectionInfoUpdated = $scope.$on('connectionHealthService.infoUpdated', function(event, data) {\r\n //$log.debug('Main controller got connectionHealthService.infoUpdated', data);\r\n $scope.connectionInfo.latency = data.latency;\r\n });\r\n\r\n //var unbindMapInit = $scope.$on('mapInitialized', function(event, map) {\r\n // $timeout(function() {\r\n // $log.debug('map Initialized - resizing');\r\n // google.maps.event.trigger(map, 'resize');\r\n // }, 500);\r\n //});\r\n\r\n var unbindSpeaking = $scope.$on('wtcpjsService.endpoint.speaking', function(event, data) {\r\n $log.debug(`endpoint speaking ${data.started ? 'started' : 'ended'}`);\r\n });\r\n\r\n var unbindMakingCall = $scope.$on('makingCall', function(e, data) {\r\n $scope.setViewMode('talk-groups');\r\n });\r\n\r\n var unbindCallOfferReceived = $scope.$on('privateCallService.callOfferReceived', (e, data) => {\r\n $scope.callOffer.callInfo = data;\r\n $scope.inboundCall = true;\r\n });\r\n \r\n var unbindCallHangupReceived = $scope.$on('privateCallService.callHangupReceived', () => {\r\n $scope.inboundCall = false;\r\n $scope.callOffer.answering = false;\r\n });\r\n\r\n var unbindPrivateCallChannelClosed = $scope.$on('privateCallChannelClosed', (e, channel) => {\r\n if($scope.selectedChannelId === channel.id)\r\n for(var c in $scope.channels) {\r\n channelModel.selectChannel(c);\r\n break;\r\n }\r\n });\r\n\r\n var unbindDispositionSet = $scope.$on('dispositionService.dispositionSet', (e, disposition) => {\r\n $scope.status.selected = disposition.toLowerCase();\r\n if(disposition === 'Phone') {\r\n $scope.showStatusSelector = false;\r\n } else {\r\n $scope.showStatusSelector = true;\r\n }\r\n });\r\n\r\n var unbindIdleStart = $scope.$on('IdleStart', () => {\r\n let _myEndpoint = endpointModel.getMyEndpoint();\r\n if(_myEndpoint.disposition !== 'Phone') {\r\n dispositionService.setDisposition(endpointModel.getMyEndpoint().id, 'Idle');\r\n }\r\n });\r\n\r\n var unbindIdleEnd = $scope.$on('IdleEnd', () => {\r\n let _myEndpoint = endpointModel.getMyEndpoint();\r\n if(_myEndpoint.disposition !== 'Phone') {\r\n dispositionService.setDisposition(endpointModel.getMyEndpoint().id, 'Ready');\r\n }\r\n });\r\n\r\n $scope.$on('$destroy', function() {\r\n unbindPrivateCallChannelsCleared();\r\n unbindReconnecting();\r\n unbindPrivateCallChannelClosed();\r\n unbindCallHangupReceived();\r\n unbindCallOfferReceived();\r\n unbindChannelSelected();\r\n unbindChannelsUpdated();\r\n unbindChannelPropertiesRecieved();\r\n unbindSettingsClose();\r\n unbindProfileNameChanged();\r\n unbindChannelRemoved();\r\n unbindOpenFullscrenMap();\r\n unbindCloseFullscreenMap();\r\n unbindActiveChannelsChanged();\r\n //unbindMapInit();\r\n unbindSpeaking();\r\n unbindMakingCall();\r\n unbindPrivateCallChannelAdded();\r\n unbindConnectionInfoUpdated();\r\n unbindDispositionSet();\r\n unbindIdleStart();\r\n unbindIdleEnd();\r\n $log.debug('MainController destroyed');\r\n })();\r\n\r\n init();\r\n }\r\n ])\r\n .config([\"IdleProvider\", function(IdleProvider) {\r\n IdleProvider.idle(300);\r\n IdleProvider.timeout(false);\r\n }])\r\n .run(['Idle', function(Idle) {\r\n Idle.watch();\r\n }]);\r\n \r\n","angular\r\n .module('webcomm').filter('activeChannels', function() {\r\n return function(input) {\r\n var out = {};\r\n\r\n angular.forEach(input, (value, key) => {\r\n if (value && value.hasOwnProperty('active') && value.active)\r\n out[key] = value;\r\n });\r\n\r\n return out;\r\n }\r\n });","angular\r\n .module('webcomm').filter('sharingLocation', function() {\r\n return function(input) {\r\n var out = {};\r\n\r\n angular.forEach(input, (value, key) => {\r\n if (value && value.hasOwnProperty('location') && value.location)\r\n out[key] = value;\r\n });\r\n\r\n return out;\r\n }\r\n });","angular\r\n .module('webcomm')\r\n .filter('truncate', function () {\r\n return function (value, max = 20, tail = '…') {\r\n if (!value) return '';\r\n if (!max) return value;\r\n if (value.length <= max) return value;\r\n\r\n value = value.substr(0, max);\r\n // if (wordwise) {\r\n // var lastspace = value.lastIndexOf(' ');\r\n // if (lastspace != -1) {\r\n // //Also remove . and , so its gives a cleaner result.\r\n // if (value.charAt(lastspace-1) == '.' || value.charAt(lastspace-1) == ',') {\r\n // lastspace = lastspace - 1;\r\n // }\r\n // value = value.substr(0, lastspace);\r\n // }\r\n // }\r\n\r\n return value + tail;\r\n };\r\n});","(function(angular) {\r\n \"use strict\";\r\n var channels, selectedChannelId, privateCallChannelId = -1, privateCallChannels;\r\n\r\n var spc = {\r\n id: 0,\r\n name: 'System Presence Channel',\r\n active: true\r\n };\r\n\r\n var ChannelData = function(wtcpjsChannel, isActive) {\r\n return {\r\n id: wtcpjsChannel.channelId,\r\n name: wtcpjsChannel.channelName,\r\n\r\n active: isActive,\r\n ready: false,\r\n canTransmitAudio: false,\r\n canReceiveAudio: false,\r\n isSimplex: false,\r\n numEndpoints: 0,\r\n isRxOnlyChannel: false,\r\n update(name, canTransmitAudio, canReceiveAudio, isSimplex) {\r\n this.name = name;\r\n this.canTransmitAudio = canTransmitAudio;\r\n this.canReceiveAudio = canReceiveAudio;\r\n this.isRxOnlyChannel = !canTransmitAudio && canReceiveAudio; \r\n this.isSimplex = isSimplex;\r\n }\r\n };\r\n };\r\n\r\n class PrivateCallChannelData extends ChannelData {\r\n constructor(wtcpjsChannel, isActive) {\r\n super(wtcpjsChannel, isActive);\r\n this.callType = 0; // 1: Endpoint call, 2: E164 Number\r\n this.callActive = false;\r\n this.calleeNumber = \"\";\r\n this.calleeName = \"\";\r\n this.callId = 0;\r\n this.participantId = \"\";\r\n }\r\n }\r\n\r\n class ChannelModel {\r\n constructor($rootScope, $q, $log, settingsService) {\r\n this.$q = $q;\r\n this.$rootScope = $rootScope;\r\n this.$log = $log;\r\n this.ChannelData = ChannelData;\r\n this.PrivateCallChannelData = PrivateCallChannelData;\r\n\r\n this.settingsSvc = settingsService;\r\n channels = {};\r\n privateCallChannels = {};\r\n selectedChannelId = 0;\r\n }\r\n addOrUpdateChannel(channel) {\r\n let chan = channels[channel.id];\r\n if (!chan) {\r\n // Check if user ever updated talk group settings, if so use those. Otherwise default active flag to true\r\n let channelSelections = this.settingsSvc.getChannelSelection();\r\n let isActive = (typeof channel.active != 'undefined') ?\r\n channel.active :\r\n channelSelections[channel.channelId] && !channelSelections[channel.channelId].active ? false : true;\r\n chan = new ChannelData(channel, isActive);\r\n }\r\n\r\n channels[chan.id] = chan;\r\n this.$rootScope.$broadcast('channelModel.channelsUpdated', channels);\r\n }\r\n addEmptyChannel(channelId) {\r\n this.addOrUpdateChannel({\r\n channelId: channelId\r\n }, true); // isActive = true\r\n }\r\n addOrUpdatePrivateCallChannel(callType, fromUserName, toUserName, toCallAlias, calleeName, callId, participantId, barge) {\r\n const key = fromUserName + toUserName;\r\n let name = calleeName;\r\n let pcChan = privateCallChannels[key];\r\n if (!pcChan) {\r\n pcChan = new PrivateCallChannelData({ channelId: privateCallChannelId--, channelName: name }, true);\r\n pcChan.callType = callType;\r\n pcChan.calleeNumber = toCallAlias;\r\n pcChan.calleeName = calleeName;\r\n pcChan.participantId = participantId;\r\n pcChan.bargeCall = barge;\r\n channels[pcChan.id] = privateCallChannels[key] = pcChan;\r\n this.$rootScope.$broadcast('channelModel.privateCallChannelAdded', pcChan);\r\n } \r\n\r\n pcChan.callId = callId;\r\n pcChan.active = true;\r\n \r\n return pcChan.id;\r\n }\r\n addOrUpdateAndSelectPrivateCallChannel(myUser, targetUser) {\r\n let channel = this.addOrUpdatePrivateCallChannel(2, myUser.userName, targetUser.userName, targetUser.callAlias, targetUser.displayName, null, targetUser.userName);\r\n this.selectChannel(channel);\r\n }\r\n getChannel(channelId) {\r\n return channelId ? channels[channelId] : spc;\r\n }\r\n getChannels() {\r\n return channels;\r\n }\r\n getActiveChannelIds() {\r\n return Object.keys(channels).filter(id => channels[id].active);\r\n }\r\n areAnyChannelsActive() {\r\n return this.getActiveChannelIds().length > 0;\r\n }\r\n selectChannel(channelId) {\r\n let channel = channels[channelId];\r\n\r\n // If selecting a private call channel make sure its active\r\n // It might have been closed by the user but they are selecting it from activities\r\n if(channel.id < 0) {\r\n channel.active = true;\r\n }\r\n // reset endpoint info.\r\n //Do this in endpointsModel -> endpoints = {};\r\n selectedChannelId = channelId;\r\n\r\n this.$log.debug(\"channelModel.selectChannel \" + channelId);\r\n\r\n // FIRST we get the components ready by notifying that the channel is being selected\r\n this.$rootScope.$broadcast('channelModel.channelSelected', channel);\r\n }\r\n clearSelectedChannel() {\r\n selectedChannelId = 0;\r\n }\r\n getSelectedChannel() {\r\n return channels[selectedChannelId];\r\n }\r\n selectFirstActiveChannel() {\r\n let that = this;\r\n let activeChannelIds = this.getActiveChannelIds();\r\n if (!activeChannelIds.includes(selectedChannelId)) {\r\n this.$rootScope.$applyAsync(function ($scope) {\r\n that.selectChannel(activeChannelIds[0]);\r\n });\r\n }\r\n }\r\n areChannelsNewOrChanged(wtcpjsChannels) {\r\n return wtcpjsChannels.length !== Object.keys(channels).length || !wtcpjsChannels.every((e, i, a) => { return channels.hasOwnProperty(e.channelId); });\r\n }\r\n\r\n reconnectedWithReducedActiveChannels(wtcpjsChannels) {\r\n return this.getActiveChannelIds().length > 0 && wtcpjsChannels.length !== this.getActiveChannelIds().length;\r\n } \r\n removeChannel(channelId) {\r\n delete channels[channelId];\r\n this.$log.debug('channelMode.channelRemoved ' + channelId);\r\n this.$rootScope.$broadcast('channelModel.channelRemoved', channelId);\r\n }\r\n resetReadyState(channelIds) {\r\n for (var x in channelIds) {\r\n if(channels.hasOwnProperty(channelIds[x])) {\r\n channels[channelIds[x]].ready = false;\r\n }\r\n }\r\n }\r\n clearPrivateCallChannels() {\r\n privateCallChannels = {};\r\n\r\n this.$rootScope.$broadcast('channelModel.privateCallChannelsCleared');\r\n }\r\n clearChannels() {\r\n // When clearing channels, the intent is to only clear public talkgroup channels\r\n // If there are any private call channels lets make sure to copy them back in\r\n channels = {};\r\n Object.getOwnPropertyNames(privateCallChannels).forEach((key) => {\r\n channels[privateCallChannels[key].id] = privateCallChannels[key];\r\n });\r\n\r\n selectedChannelId = null;\r\n this.$rootScope.$broadcast('channelModel.channelsCleared');\r\n }\r\n }\r\n\r\n angular\r\n .module('webcomm')\r\n .service('channelModel', ['$rootScope', '$q', '$log', 'settingsService', ChannelModel]);\r\n})(angular);\r\n","(function(angular) {\r\n var privateEndpoints, channelEndpoints, disabledChannels, truncatedChannels, channelUsers, myEndpoint, timeout, rootScope, q, log, _initializing = true;\r\n var pendingUserJoined = [];\r\n\r\n var parseLocation = function(loc) {\r\n if (!loc) { return loc; }\r\n\r\n var locElements = loc.split(',');\r\n var location = {};\r\n\r\n var kv = null;\r\n for (let e of locElements) {\r\n kv = e.split('=');\r\n location[kv[0]] = kv[1];\r\n }\r\n\r\n return location;\r\n };\r\n\r\n var addToSet = function(val, set) {\r\n if(!set.has(val)) {\r\n set.add(val);\r\n }\r\n };\r\n\r\n var removeFromSet = function(val, set) {\r\n if(set.has(val)) {\r\n set.delete(val);\r\n }\r\n };\r\n\r\n class Endpoint {\r\n constructor(endpointId) {\r\n this.id = endpointId;\r\n this.flags = new Map();\r\n this.filterIds = [];\r\n this.locTimeout = null;\r\n this.userName = '';\r\n this.name = '';\r\n this.active = true;\r\n this.spcActive = false;\r\n this.Self = false;\r\n }\r\n }\r\n\r\n var clearLocation = function (em, endpoint, channelId) {\r\n endpoint.location = null;\r\n rootScope.$broadcast(\"endpointModel.presenceUpdated\", channelEndpoints.get(channelId), channelId, endpoint.id, endpoint.userName, []);\r\n log.debug(`Endpoint ${endpoint.id} location timed out`);\r\n };\r\n\r\n var _addEndpointToChannel = function(channelId, ep, flags) {\r\n let usersMap;\r\n let userNew = false;\r\n\r\n if(!channelEndpoints.has(channelId)) {\r\n channelEndpoints.set(channelId, new Map());\r\n }\r\n\r\n if(!channelUsers.has(channelId)) {\r\n usersMap = new Map();\r\n channelUsers.set(channelId, usersMap);\r\n } else {\r\n usersMap = channelUsers.get(channelId);\r\n }\r\n\r\n if(!usersMap.has(ep.userName)) {\r\n usersMap.set(ep.userName, new Map());\r\n userNew = true;\r\n }\r\n\r\n channelEndpoints.get(channelId).set(ep.id, ep);\r\n usersMap.get(ep.userName).set(ep.id, ep);\r\n\r\n if(channelId === 0) {\r\n ep.spcActive = true;\r\n }\r\n\r\n // If flags is null then copy from SPC\r\n _setEndpointsFlags(channelId, ep.id, flags || ep.flags.get(0));\r\n\r\n if(!_initializing && userNew) {\r\n var _func = function() {\r\n rootScope.$broadcast('endpointModel.userJoined', channelId, ep);\r\n };\r\n\r\n if(ep.name) {\r\n _func();\r\n }\r\n else {\r\n pendingUserJoined.push(_func);\r\n }\r\n }\r\n };\r\n\r\n var _setEndpointsFlags = function(channelId, endpointId, flags) {\r\n var ep = channelEndpoints.get(channelId).get(endpointId);\r\n ep.flags.set(channelId, flags);\r\n }\r\n\r\n // TBD: There is a bug here, when changing channels and there are no new endpoints (but some endpoints on prev channel aren't on selected channel)\r\n // then presenceUpdated event is not being broadcast\r\n var updatePropertyWork = function (channelId, ep) {\r\n var endpoint = privateEndpoints.get(ep.endpointId) || (function (ep) {\r\n let newEndpoint = new Endpoint(ep.endpointId);\r\n\r\n privateEndpoints.set(ep.endpointId, newEndpoint);\r\n _setEndpointsFlags(channelId, newEndpoint.id, new WtcpJs.EndpointFlags());\r\n\r\n return newEndpoint;\r\n })(ep);\r\n\r\n // Sometimes these endpoinst come from channel activity, so we won't have filter ID's\r\n // Make sure we don't assign a null value to our filter array\r\n if(ep.filterIds) {\r\n endpoint.filterIds = ep.filterIds;\r\n }\r\n // This shouldn' be happening here, this routine is just for updating EP Props and flags\r\n //_addEndpointToChannel(channelId, endpoint);\r\n\r\n let em = this;\r\n\r\n for(var prop of Object.getOwnPropertyNames(ep.properties)) {\r\n switch(prop) {\r\n case \"displayName\":\r\n\r\n // Need to check if this name already been used\r\n endpoint.name = ep.properties.displayName;\r\n break;\r\n case \"location\":\r\n if (ep.properties.location) {\r\n endpoint.location = parseLocation(ep.properties.location);\r\n if (endpoint.locTimeout) {\r\n timeout.cancel((endpoint.locTimeout));\r\n }\r\n\r\n endpoint.locTimeout = timeout(clearLocation, 330000, false, em, endpoint, channelId);\r\n } else {\r\n if (endpoint.locTimeout) {\r\n timeout.cancel(endpoint.locTimeout);\r\n clearLocation(em, endpoint, channelId);\r\n }\r\n }\r\n break;\r\n default:\r\n // log.debug(`>> Updateing EP ${ep.name}, property ${prop}= value ${ep.properties[prop]}`);\r\n endpoint[prop] = ep.properties[prop];\r\n }\r\n }\r\n\r\n if(pendingUserJoined.length > 0) {\r\n pendingUserJoined.pop()();\r\n }\r\n\r\n return endpoint;\r\n }\r\n\r\n class EndpointModel {\r\n constructor($rootScope, $timeout, $q, $log) {\r\n q = $q;\r\n rootScope = $rootScope;\r\n log = $log;\r\n timeout = $timeout;\r\n\r\n channelEndpoints = new Map();\r\n disabledChannels = new Set();\r\n truncatedChannels = new Set();\r\n channelUsers = new Map();\r\n privateEndpoints = new Map();\r\n }\r\n getEndpoint(endpointId) {\r\n return privateEndpoints.get(endpointId);\r\n }\r\n getChannelEndpoint(channelId, endpointId) {\r\n if (channelEndpoints.has(channelId)) {\r\n return channelEndpoints.get(channelId).get(endpointId);\r\n }\r\n else {\r\n return null;\r\n }\r\n }\r\n getEndpoints() {\r\n return privateEndpoints;\r\n }\r\n\r\n /**\r\n * Associate an endpoint with a channel\r\n * @param [number] channelId\r\n * @param ep\r\n * @param flags\r\n */\r\n addEndpointToChannel(channelId, ep, flags, silent = false) {\r\n _addEndpointToChannel(channelId, ep, flags);\r\n\r\n if(!silent) {\r\n rootScope.$broadcast(\"endpointModel.presenceUpdated\", channelEndpoints.get(channelId), channelId, ep.id, ep.userName, []);\r\n }\r\n }\r\n setEndpointsDisabledOnChannel(channelId, maxEndpointsOnChannel) {\r\n addToSet(channelId, disabledChannels);\r\n rootScope.$broadcast(\"endpointModel.endpointsDisabledOnChannel\", channelId, maxEndpointsOnChannel);\r\n }\r\n clearEndpointsDisabledOnChannel(channelId) {\r\n removeFromSet(channelId, disabledChannels);\r\n rootScope.$broadcast(\"endpointModel.endpointsEnabledOnChannel\", channelId);\r\n }\r\n setEndpointsTruncatedOnChannel(channelId) {\r\n addToSet(channelId, truncatedChannels);\r\n }\r\n clearEndpointsTruncatedOnChannel(channelId) {\r\n removeFromSet(channelId, truncatedChannels);\r\n }\r\n endpointsDisabledOnChannel(channelId) {\r\n return disabledChannels.has(channelId);\r\n }\r\n endpointsTruncatedOnChannel(channelId) {\r\n return truncatedChannels.has(channelId);\r\n }\r\n getChannelEndpoints(channelId) {\r\n if (channelEndpoints.has(channelId)) {\r\n return channelEndpoints.get(channelId);\r\n }\r\n\r\n return new Map();\r\n }\r\n getChannelUsers(channelId) {\r\n if (channelUsers.has(channelId)) {\r\n return channelUsers.get(channelId);\r\n }\r\n\r\n return new Map();\r\n }\r\n // Used to initialize the endpointModel with data\r\n initializeEndpoints(channelId, resp) {\r\n _initializing = true;\r\n var length = resp.endpointPropertyInfo.length;\r\n var isLastEndpoint = false;\r\n for (var x = 0; x < length; x++) {\r\n let ep = resp.endpointPropertyInfo[x];\r\n\r\n isLastEndpoint = x !== (length - 1);\r\n\r\n this.addEndpoint(channelId, ep.endpointInfo.endpointId, ep.endpointInfo.endpointName, ep.endpointInfo.endpointFlags, isLastEndpoint);\r\n\r\n updatePropertyWork(channelId, {\r\n endpointId: ep.endpointInfo.endpointId,\r\n properties: ep.endpointProperties,\r\n filterIds: [ resp.filterId ]\r\n });\r\n }\r\n rootScope.$broadcast('endpointModel.endpointsLoaded', channelEndpoints.get(channelId));\r\n _initializing = false;\r\n }\r\n // Used for adding endpoints from onChannelActivity event data\r\n addEndpoint(channelId, endpointId, name, flags, silent) {\r\n let ep = privateEndpoints.get(endpointId);\r\n if(!ep) {\r\n ep = new Endpoint(endpointId);\r\n ep.userName = name;\r\n privateEndpoints.set(endpointId, ep);\r\n }\r\n\r\n // If endpoints are being added as the result of a setEndpointPropertyFilter there will be no\r\n // SPC channel activity. This differs from the behavior when an endpoint joins the system\r\n // and matches an existing endpoint filter. The first sign of this joining user will be activity\r\n // on the SPC, followed by an add endpoint to the private talk group channel (if there is one).\r\n // This code adds the endpoint to the SPC channel if it doesn't already exists for consistenncy\r\n if(channelId < 0 && !channelEndpoints.get(0).has(endpointId)) {\r\n this.addEndpointToChannel(0, ep, flags, silent); // 0 is the SPC channel\r\n }\r\n\r\n this.addEndpointToChannel(channelId, ep, flags, silent)\r\n\r\n if (flags.Self) {\r\n myEndpoint = ep;\r\n myEndpoint.Self = true;\r\n }\r\n\r\n return privateEndpoints.get(endpointId);\r\n }\r\n // Use to set an initial location on the endpoint, otherwise updateProperties will keep the location up-to-date\r\n setLocation(endpointId, loc) {\r\n var _ep = privateEndpoints.get(endpointId);\r\n if(_ep) {\r\n _ep.location = parseLocation(`lo=${loc.lng},la=${loc.lat}`);\r\n } else {\r\n log.warn(`Failed to setLocation for endpoint id ${endpointId}`);\r\n }\r\n }\r\n // Used for adding or updating endpoints from onEndpointPropertiesReceived event data\r\n updateProperties(channelId, ep) {\r\n var endpoint = updatePropertyWork(channelId, ep);\r\n\r\n if(endpoint.name) {\r\n rootScope.$broadcast(\"endpointModel.presenceUpdated\", channelEndpoints.get(channelId), channelId, endpoint.id, endpoint.userName, ep.filterIds);\r\n }\r\n }\r\n updateFlags(channelId, endpointId, flags) {\r\n privateEndpoints.get(endpointId).flags.set(channelId, flags);\r\n }\r\n deleteEndpoint(channelId, endpointId) {\r\n if (privateEndpoints.has(endpointId)) {\r\n let endpoint = privateEndpoints.get(endpointId);\r\n let endpointMap = channelEndpoints.get(channelId);\r\n let userName = endpoint.userName;\r\n\r\n let userMap = channelUsers.get(channelId).get(userName);\r\n\r\n let locTimeout = endpoint.locTimeout;\r\n if (locTimeout) {\r\n timeout.cancel(locTimeout);\r\n }\r\n\r\n if(endpointMap.has(endpointId)) {\r\n endpointMap.delete(endpointId);\r\n }\r\n\r\n if(userMap.has(endpointId)) {\r\n userMap.delete(endpointId);\r\n }\r\n\r\n if(userMap.size === 0) {\r\n channelUsers.get(channelId).delete(userName);\r\n rootScope.$broadcast('endpointModel.userLeft', channelId, userName, endpoint.filterIds);\r\n }\r\n\r\n // If endpoint is in contact list, there will be an EP prop update for the user leaving the SPC\r\n // Defer deleting the endpoint from the private map until channel Id 0 ep prop update comes through\r\n if(!endpoint.spcActive || channelId === 0) {\r\n privateEndpoints.delete(endpointId);\r\n }\r\n\r\n // This garbage needs to be refactored. Create endpoint joined, endpoints left events...\r\n rootScope.$broadcast(\"endpointModel.presenceUpdated\", channelEndpoints.get(channelId), channelId, endpointId, userName, endpoint.filterIds);\r\n }\r\n }\r\n getMyEndpoint() {\r\n return myEndpoint;\r\n }\r\n clearChannelEndpoints(channelId) {\r\n if(channelEndpoints.has(channelId)) {\r\n channelEndpoints.get(channelId).forEach((ep) => {\r\n timeout.cancel(ep.locTimeout);\r\n });\r\n channelEndpoints.get(channelId).clear();\r\n }\r\n if(channelUsers.has(channelId)) {\r\n channelUsers.get(channelId).clear();\r\n }\r\n }\r\n clearEndpoints() {\r\n privateEndpoints.forEach((ep) => {\r\n timeout.cancel(ep.locTimeout);\r\n });\r\n privateEndpoints.clear();\r\n channelEndpoints.clear();\r\n channelUsers.clear();\r\n _initializing = true;\r\n }\r\n }\r\n\r\n angular\r\n .module('webcomm')\r\n .service('endpointModel', ['$rootScope', '$timeout', '$q', '$log', EndpointModel]);\r\n})(angular);","(function(angular) {\r\n \"use strict\";\r\n var feed, channelFeed;\r\n\r\n class FeedModel {\r\n constructor($rootScope, $log) {\r\n this.$rootScope = $rootScope;\r\n this.$log = $log;\r\n this.MAX_ITEMS = 500;\r\n feed = [];\r\n channelFeed = new Map();\r\n\r\n $rootScope.$on('ConnectionService.logout', () => {\r\n this.clearFeed();\r\n });\r\n }\r\n\r\n getChannelFeed(channelId) {\r\n if (!channelFeed.has(channelId)) {\r\n channelFeed.set(channelId, []);\r\n }\r\n\r\n return channelFeed.get(channelId);\r\n }\r\n\r\n addChannelFeedEvent(channelId, name, type, data) {\r\n var channelFeedEvent = {\r\n \"feedId\": 0,\r\n \"channelId\": channelId,\r\n \"type\": type,\r\n \"data\": data,\r\n \"name\": name,\r\n \"confirmed\": false,\r\n \"clientTime\": new Date()\r\n }\r\n\r\n if (type !== \"end-speaking\") { // don't add the end-speaking events\r\n let feedId = feed.push(channelFeedEvent); //channelModel.getChannel(channelId).events.push(channelFeedEvent);\r\n let channelFeed = this.getChannelFeed(channelId);\r\n channelFeed.push(channelFeedEvent);\r\n\r\n if (channelFeed.length > this.MAX_ITEMS) {\r\n channelFeed.shift();\r\n }\r\n\r\n channelFeedEvent.feedId = feedId;\r\n }\r\n\r\n //this.$log.debug(\"addChannelFeedEvent: \", channelFeedEvent);\r\n this.$rootScope.$broadcast(\"feedModel.feedEventReceived\", channelFeedEvent);\r\n return channelFeedEvent;\r\n }\r\n clearFeed() {\r\n feed = [];\r\n channelFeed.clear();\r\n }\r\n }\r\n\r\n angular\r\n .module('webcomm')\r\n .service('feedModel', ['$rootScope', '$log', FeedModel]);\r\n})(angular);","(function(angular) {\r\n \"use strict\";\r\n let profiles = {}, selectedProfile;\r\n\r\n class ProfileModel {\r\n constructor($rootScope, $q, $log) {\r\n this.$q = $q;\r\n this.$rootScope = $rootScope;\r\n this.$log = $log;\r\n }\r\n\r\n setProfiles(p) {\r\n profiles = {};\r\n for (let profile of p) {\r\n profiles[profile.profileId] = profile;\r\n }\r\n }\r\n\r\n getProfiles() {\r\n return profiles;\r\n }\r\n\r\n getSelectedProfile() {\r\n return selectedProfile;\r\n }\r\n\r\n selectProfile(profile, channels) {\r\n let id = '';\r\n if (profile) {\r\n id = typeof profile === \"object\" && profile.hasOwnProperty(\"profileId\") ? profile.profileId : profile;\r\n }\r\n else {\r\n throw \"profileModel: profile parameter must be a valid profile or profile Id\";\r\n }\r\n\r\n if (profiles.hasOwnProperty(id)) {\r\n selectedProfile = profiles[id];\r\n profiles[id].channels = channels.map(c => { return c.channelId; });\r\n } else {\r\n throw \"profileModel: profile does not exist\";\r\n }\r\n }\r\n\r\n getChannelIdsForProfile(profileId) {\r\n return profiles[profileId].channels;\r\n }\r\n\r\n addChannelToCurrentProfile(channelId) {\r\n this.getSelectedProfile().channels.push(channelId);\r\n }\r\n\r\n removeChannelFromCurrentProfile(channelId) {\r\n delete this.getSelectedProfile().channels[channelId];\r\n }\r\n\r\n updateProfileName(name) {\r\n if(selectedProfile) {\r\n profiles[selectedProfile.profileId].name = name;\r\n }\r\n }\r\n }\r\n\r\n angular\r\n .module('webcomm')\r\n .service('profileModel', ['$rootScope', '$q', '$log', ProfileModel]);\r\n})(angular);\r\n","angular.module('webcomm')\r\n .directive('logDisplay', function () {\r\n return {\r\n templateUrl: 'app/logDisplay/logDisplay.html',\r\n replace: true,\r\n controller: 'LogDisplay',\r\n controllerAs: 'logDisplay'\r\n }\r\n })\r\n .controller('LogDisplay', ['$rootScope', 'logger', function ($rootScope, logger) {\r\n this.showLog = false;\r\n\r\n this.hideLog = ($event) => {\r\n this.showLog = false;\r\n }\r\n\r\n this.levelClasses = {\r\n 'debug': 'text-muted',\r\n 'log': 'text-primary',\r\n 'warn': 'text-warning',\r\n 'info': 'text-info',\r\n 'error': 'text-danger'\r\n };\r\n\r\n this.selectAll = ($event) => {\r\n var range = document.createRange();\r\n range.setStart($(\"#log-list-panel\")[0], 0);\r\n range.setEnd($(\"#log-display-range-marker\")[0], 0);\r\n \r\n window.getSelection().removeAllRanges();\r\n window.getSelection().addRange(range);\r\n }\r\n\r\n this.logMessages = logger.messages;\r\n\r\n let unbindOnShowLogDisplay = $rootScope.$on('logDisplay.show', (e, x) => {\r\n this.logMessages = logger.messages;\r\n this.showLog = true;\r\n });\r\n \r\n $rootScope.$on('$destroy', () => unbindOnShowLogDisplay());\r\n }]);","angular.module('webcomm')\r\n .directive('logDisplayLink', function () {\r\n return {\r\n template: '
',\r\n replace: true,\r\n controller: 'LogDisplayLink'\r\n }\r\n })\r\n .controller('LogDisplayLink', ['$scope', function ($scope) {\r\n $scope.showLog = () => {\r\n $scope.$emit('logDisplay.show');\r\n }\r\n }]);","angular\r\n .module('webcomm')\r\n .factory('anchorInfoService', ['$log', '$timeout', '$rootScope', function ($log, $timeout, $rootScope) {\r\n // This is a very basic implementation. The Proxy as of build 5.12.61981 ignores anchor info. This service\r\n // will need to be heavily modified once we start implementing \"virtual\" views\r\n\r\n /**** Anchor type\r\n 1.\tRowIndex\r\n 2.\tPercent\r\n 3.\tPage\r\n 4.\tStart Char (UTF-8 char code)\r\n 5.\tOffset\r\n ****/\r\n const pageSize = 100; \r\n let service = {\r\n\r\n createAnchor() {\r\n $log.debug(\"anchorInfoService: creating a new AnchorInfo for getting first \" + pageSize + \" entries\");\r\n let ai = new WtcpJs.AnchorInfo();\r\n ai.value = 0; // start first list\r\n ai.type = 1; // Row Index\r\n ai.before = 0;\r\n ai.after = pageSize - 1;\r\n return ai;\r\n },\r\n\r\n getNextSet(ai) {\r\n ai.value += pageSize; // add it by pageSize\r\n ai.type = 1; // row index\r\n ai.before = 0;\r\n ai.after += pageSize;\r\n $log.debug(\"getNext : value=\"+ai.value+\",type=\"+ai.type+\",before=\"+ai.before+\",after=\"+ai.after);\r\n return ai;\r\n },\r\n\r\n getNextAnchorOnStartChar(key) {\r\n $log.debug(\"getNextPageBasedOnStartChar [\" + key + \"]\");\r\n let ai = new WtcpJs.AnchorInfo(); \r\n ai.value = key.charCodeAt(0);\r\n ai.type = 4; //start Char based\r\n ai.before = 0;\r\n ai.after = pageSize;\r\n return ai;\r\n }\r\n }\r\n\r\n return service;\r\n }]);","class AudioService {\r\n constructor($rootScope, $log, wtcpjsClientProviderService, settingsService) {\r\n this._client = wtcpjsClientProviderService.getClient();\r\n this._log = $log;\r\n this._rootScope = $rootScope;\r\n this._settingsService = settingsService;\r\n\r\n this._rootScope.$on('ConnectionService.login', () => {\r\n let volume = this._settingsService.getVolume();\r\n this.adjustVolume(volume);\r\n });\r\n }\r\n\r\n adjustVolume(percentScale) {\r\n this._client.setVolume(percentScale);\r\n }\r\n}\r\n\r\nangular.module('webcomm').service('audioService', ['$rootScope', '$log', 'wtcpjsClientProviderService', 'settingsService', AudioService]);","/**\r\n * @typedef AuthResult\r\n * @type Object\r\n * @property {string} errorCode Error code returned\r\n * @property {string} errorDescription Error description returned\r\n * @property {string} userId The user ID - undefined if error\r\n * @property {string} accessToken Access Token - undefined if error\r\n */\r\nclass AuthResult {\r\n constructor(error, userId, accessToken, url) {\r\n if (error) {\r\n this.errorCode = Number(error.Code);\r\n this.errorMessage = error.Description;\r\n }\r\n\r\n this.userId = userId;\r\n this.accessToken = accessToken;\r\n this.url = url;\r\n this._authUrl = null;\r\n }\r\n\r\n /**\r\n * Returns whether the result was a success\r\n * @returns {boolean}\r\n */\r\n get isSuccess() {\r\n return !this.errorCode;\r\n }\r\n\r\n /**\r\n * Factory for failed AuthResults\r\n * @param {string} message The error message from the server\r\n */\r\n static Fail(error) {\r\n return new AuthResult(error);\r\n }\r\n\r\n /**\r\n * Factory for successful AuthResults\r\n * @param {string} userId The user ID from the server\r\n * @param {string} accessToken The token from the server\r\n */\r\n static Success(data) {\r\n let info = data.VoiceStackInfo;\r\n return new AuthResult(null, info.UserId, info.AccessToken, info.Uri);\r\n }\r\n}\r\n\r\nclass AuthService {\r\n constructor($q, $http, $log, $location, $routeParams) {\r\n this._q = $q;\r\n this._http = $http;\r\n this._log = $log;\r\n this._location = $location;\r\n this._params = $routeParams;\r\n this._validDomains = [ 'wavecloudconnect', 'waveoncloud' ];\r\n }\r\n\r\n /**\r\n * Authenticate against provisioning server\r\n * @param {string} server The provisioning server URL.\r\n * @param {string} username Voice stack username.\r\n * @param {string} password Voice stack password.\r\n * @return {AuthResult}\r\n */\r\n getToken(server, username, password) {\r\n\r\n let credentials = {username, password, scopes: 'voice_stack_access'};\r\n\r\n return this._http({\r\n method: 'POST',\r\n url: server,\r\n data: $.param(credentials),\r\n headers: {'Content-Type': 'application/x-www-form-urlencoded'}\r\n })\r\n .then((response) => {\r\n this._log.info(\"AuthService.getToken SUCCESS: \", response.data);\r\n return AuthResult.Success(response.data);\r\n })\r\n .catch((err) => {\r\n this._log.error(\"AuthService.getToken ERROR: \", err.data ? err.data[0] : err);\r\n\r\n if (err.status < 0)\r\n throw new Error(\"Could not connect to provisioning server at \" + server);\r\n else\r\n return AuthResult.Fail(err.data[0]);\r\n });\r\n }\r\n\r\n getAuthFragment(path) {\r\n let regex = /https:\\/\\/(.*)\\.(.*)\\.com/;\r\n let match = regex.exec(path);\r\n\r\n if (match && match.length === 3) {\r\n let env = match[1].split('-')[0];\r\n let domain = match[2];\r\n\r\n if (this._validDomains.includes(match[2])) {\r\n let oAuthPath = 'WaveIdps/OAuth2Token';\r\n if (env === 'voice') {\r\n return `https://prod.${domain}.com/${oAuthPath}`;\r\n } else {\r\n return `https://${env}.${domain}.com/${oAuthPath}`;\r\n }\r\n }\r\n }\r\n\r\n return \"\";\r\n }\r\n\r\n getAuthUrl() {\r\n var _this = this;\r\n if(this._authUrl) {\r\n return this._q.when(this._authUrl);\r\n } else if( this._params.mode && this._params.mode === 'oncloud') {\r\n /*let path = this._location.absUrl();\r\n this._authUrl = this.getAuthFragment(path);\r\n return this._authUrl;*/\r\n return this._http.get('oauth.json')\r\n .then((response) => {\r\n _this._authUrl = response.data.oauthurl;\r\n return _this._authUrl;\r\n })\r\n .catch(() => {\r\n throw new Error(\"Server is not configured for WAVE OnCloud\");\r\n });\r\n } else {\r\n return this._q.when(null);\r\n }\r\n }\r\n\r\n get authUrlPath() {\r\n if (this.authUrl)\r\n return `/oncloud`;\r\n else\r\n return \"/\";\r\n }\r\n\r\n get loginPath() {\r\n if (this.authUrl)\r\n return this.authUrlPath;\r\n else {\r\n if(this._params.mode)\r\n return `/${this._params.mode}`;\r\n else\r\n return '/';\r\n }\r\n }\r\n}\r\n\r\nangular.module('webcomm').service('authService', ['$q', '$http', '$log', '$location', '$routeParams', AuthService]);\r\n\r\n/*\r\n POST http://dev.wavecloudconnect.com/presentation/WaveIdps/OAuth2Token\r\n HEADERS\r\n Accept: application/json\r\n BODY (url x-www-form-urlencoded):\r\n username:rdtg76@motorolasolutions.com\r\n password:xxxxxxxxx1\r\n scopes:voice_stack_access\r\n\r\n Error:\r\n [\r\n {\r\n \"Code\": \"3\",\r\n \"Description\": \"No VoiceStack access\"\r\n }\r\n ]\r\n Success:\r\n {\r\n \"VoiceStackInfo\": {\r\n \"Uri\": \"http://waas-mgmt-wps1.wavecloudconnect.com/\",\r\n \"UserId\": \"{15501d52-9d03-4cff-b193-e85613167de3}\",\r\n \"AccessToken\": \"xxx\"\r\n }\r\n }\r\n\r\n http://dev.wavecloudconnect.com/Presentation/Dashboard\r\n */","class ConnectionHealthService {\r\n constructor(wtcpjsClientProviderService, $rootScope, $log) {\r\n this.client = wtcpjsClientProviderService.getClient();\r\n\r\n this.client.onConnectionInfoUpdated.subscribe((data) => {\r\n $rootScope.$applyAsync(($scope) => {\r\n $rootScope.$broadcast(\"connectionHealthService.infoUpdated\", data);\r\n });\r\n });\r\n }\r\n pingServer() {\r\n //Doesn't do anything now, but maybe could add way to force connection health info to update\r\n }\r\n}\r\n\r\nangular.module('webcomm').service('connectionHealthService', ['wtcpjsClientProviderService', '$rootScope', '$log', ConnectionHealthService]);","class ConnectionService {\r\n constructor($rootScope, $q, $location, $log, $timeout, wtcpjsClientProviderService, persistenceService, profileModel, authService, mapLoaderService) {\r\n this.client = wtcpjsClientProviderService.getClient;\r\n\r\n this.$q = $q;\r\n this.$rootScope = $rootScope;\r\n this.$location = $location;\r\n this.$log = $log;\r\n this.$timeout = $timeout;\r\n this.wtcpjsClientProviderService = wtcpjsClientProviderService;\r\n this.persistenceService = persistenceService;\r\n this.profileModel = profileModel;\r\n this.authService = authService;\r\n this.mapLoaderService = mapLoaderService;\r\n\r\n this.userLoggingIn = false;\r\n this.forcedDisconnect = false;\r\n this.accountDisabled = false;\r\n this.userLoggedInTooMany = false;\r\n this.tryAgain = false;\r\n this.isReconnecting = false;\r\n this.isReconnectCanceled = false;\r\n this.sessionTimedOut = false;\r\n this.userNoProfiles = false;\r\n this.unsubscribeChannelActivity = null;\r\n \r\n this.client().onConnectionClosed.subscribe( (err) => {\r\n $log.warn(\"ConnectionService.onConnectionClosed\", err);\r\n this.disconnect();\r\n $rootScope.$emit(\"ConnectionService.connectionClosed\", this.isReconnecting);\r\n });\r\n\r\n this.client().onSessionClosed.subscribe(data => {\r\n $log.warn(\"ConnectionService.onSessionClosed, data: \", data);\r\n if(!this.userLoggingIn) {\r\n switch (data.errorCode) {\r\n case 0:\r\n this.forcedDisconnect = true;\r\n break;\r\n case 7:\r\n this.accountDisabled = true;\r\n break;\r\n case 19:\r\n this.tryAgain = true;\r\n break;\r\n case 23:\r\n this.userLoggedInTooMany = true;\r\n break;\r\n case 34:\r\n this.sessionTimedOut = true;\r\n break;\r\n case 52:\r\n this.userNoProfiles = true;\r\n break;\r\n }\r\n }\r\n });\r\n }\r\n \r\n getCurrentUser() {\r\n return this.currentUser;\r\n }\r\n\r\n setCurrentUser(name, password, server, profileId) {\r\n //Proxy should return a server id that is unique for the system, not per proxy\r\n //If this is ever implemented, use that ID so we can store our user info once\r\n //no matter if there are multiple valid url's or if the user enters the ip address\r\n //for the Management Server instance. Using the server string has this draw back\r\n \r\n //Uncomment this when they add unique server id\r\n //this.persistenceService.updateUserInfo(name, profile, this.client().ServerId); \r\n \r\n //Do this for now\r\n this.persistenceService.updateUserInfo(name, profileId, server);\r\n this.currentUser = { name, password, server };\r\n this.$log.debug('connectionService.currentUser: ', { name: this.currentUser.name, server: this.currentUser.name });\r\n }\r\n\r\n awaitSPCActivity(func) {\r\n if(this.unsubscribeChannelActivity) {\r\n this.unsubscribeChannelActivity();\r\n }\r\n\r\n var svc = this;\r\n this.unsubscribeChannelActivity = this.client().onChannelActivity.subscribe((data) => {\r\n svc.unsubscribeChannelActivity();\r\n svc.unsubscribeChannelActivity = null;\r\n\r\n var epId = data.endpoints[0].endpointInfo.endpointId;\r\n\r\n this.$rootScope.$broadcast('ConnectionService.login', {\r\n server: this.managementServerUrl,\r\n endpointId: epId\r\n });\r\n\r\n if(func) {\r\n func(epId);\r\n }\r\n });\r\n }\r\n\r\n reconnect(profileId) {\r\n\r\n profileId = profileId || this.profileModel.getSelectedProfile().profileId;\r\n\r\n let user = this.currentUser;\r\n let svc = this;\r\n this.$log.warn(`reconnecting to ${this.managementServerUrl}`);\r\n this.isReconnecting = true;\r\n\r\n this.$rootScope.$applyAsync(($scope) => {\r\n $scope.$broadcast('isReconnecting', true);\r\n\r\n return this.client()\r\n .connect(\r\n this.managementServerUrl,\r\n user.name,\r\n user.password,\r\n profileId)\r\n .then((data) => {\r\n svc.isReconnectCanceled = false;\r\n svc.$rootScope.$applyAsync(($scope) => {\r\n svc.$log.warn('reconnected');\r\n this.awaitSPCActivity((endpointId) => { svc.$rootScope.$broadcast('isReconnecting', svc.isReconnecting, endpointId);} );\r\n svc.setProfileSuccess(true, profileId, data.channels, user.name, user.password, data.phoneLines, data.configInfo);\r\n svc.isReconnecting = false;\r\n svc.userLoggingIn = false;\r\n svc.tryAgain = false;\r\n });\r\n })\r\n .catch((err) => {\r\n svc.$rootScope.$applyAsync(function($scope) {\r\n svc.$log.warn('reconnect failed - ', err);\r\n if (svc.isReconnecting) {\r\n switch(err.errorCode) {\r\n case 7:\r\n svc.accountDisabled = true;\r\n svc.isReconnecting = false;\r\n svc.$rootScope.$broadcast('isReconnecting', svc.isReconnecting);\r\n break;\r\n case 8: // Removed from profile\r\n svc.$location.path(svc.authService.loginPath);\r\n svc.login(svc.currentUser.server, svc.currentUser.name, svc.currentUser.password)\r\n .then((profiles) => {\r\n svc.isReconnecting = false;\r\n svc.$rootScope.$broadcast('isReconnecting', svc.isReconnecting);\r\n\r\n if (profiles.length === 1) {\r\n svc.setProfile(svc.currentUser.name, svc.currentUser.password, profiles[0]);\r\n svc.$location.path('/main' + svc.authService.authUrlPath);\r\n } else {\r\n svc.isReconnectCanceled = true;\r\n svc.$rootScope.$broadcast('connectionService.selectNewProfile', profiles);\r\n }\r\n });\r\n break;\r\n case 52:\r\n svc.isReconnecting = false;\r\n svc.$rootScope.$broadcast('isReconnecting', svc.isReconnecting);\r\n\r\n svc.userNoProfiles = true;\r\n svc.disconnect();\r\n break;\r\n default:\r\n svc.reconnectTimeout = svc.$timeout(() => svc.reconnect(), 2000);\r\n break;\r\n }\r\n }\r\n });\r\n });\r\n });\r\n }\r\n\r\n cancelReconnect() {\r\n this.$log.warn(\"reconnect CANCELLED\");\r\n this.isReconnecting = false;\r\n this.isReconnectCanceled = true;\r\n\r\n if (this.reconnectTimeout) {\r\n this.$timeout.cancel(this.reconnectTimeout);\r\n }\r\n\r\n this.logoutWithError('Problems connecting to server. Please check your connection');\r\n }\r\n\r\n disconnect() {\r\n this.$log.debug('disconnecting', this.currentUser.name, this.currentUser.server);\r\n this.client().AudioPlayerActive = false; //Silence the audio player immediately\r\n\r\n if (this.currentUser) {\r\n if (this.forcedDisconnect) { //Socket was closed from forced disconnect - do not reconnect\r\n this.forcedDisconnect = false; //Reset state\r\n this.logoutWithError('Your session has been forcibly terminated');\r\n } else if (this.accountDisabled) {\r\n this.accountDisabled = false; //Reset state\r\n this.logoutWithError('Your account has been disabled');\r\n } else if(this.userNoProfiles) {\r\n this.userNoProfiles = false; // Reset state\r\n this.logoutWithError(\"You must have at least one Profile to use WAVE. Please contact your administrator\");\r\n } else if (!this.userLoggedInTooMany && !this.userLoggingIn && !this.isReconnectCanceled && !this.isReconnecting) {\r\n this.reconnect();\r\n }\r\n }\r\n }\r\n\r\n getAndResetLogoutError() {\r\n let error = this.logoutError;\r\n this.logoutError = undefined;\r\n return error;\r\n }\r\n\r\n logoutWithError(error) {\r\n this.logout();\r\n this.logoutError = error;\r\n this.$location.path(this.authService.loginPath);\r\n }\r\n\r\n createServerUrl(server, isOnSecurePage) {\r\n const wsRegex = /^ws{1,2}:\\/\\//;\r\n const httpsRegex = /^https?:\\/\\//;\r\n const endsInWaveRegex = /\\/wave$/;\r\n\r\n const isRequestingInsecure = server.startsWith(\"http://\") || server.startsWith(\"ws://\");\r\n if (isOnSecurePage && isRequestingInsecure)\r\n throw new Error(\"MixedContent\");\r\n\r\n let serverUrl = server;\r\n if (!(serverUrl.match(wsRegex) || serverUrl.match(httpsRegex))) {\r\n serverUrl = `https://${server}`;\r\n }\r\n\r\n return serverUrl;\r\n }\r\n\r\n login(managementServerUrl, username, password) {\r\n this.isReconnectCanceled = false;\r\n this.userLoggingIn = true;\r\n\r\n const defer = this.$q.defer();\r\n\r\n let serverUrl;\r\n try {\r\n const isSecure = window.location.protocol === \"https:\";\r\n serverUrl = this.createServerUrl(managementServerUrl, isSecure);\r\n } catch (ex) {\r\n defer.reject(\"You cannot open an insecure connection from a secure page\");\r\n }\r\n\r\n this.$log.debug(`connecting to ${serverUrl}, (${username})`);\r\n\r\n this.managementServerUrl = serverUrl;\r\n\r\n this.client()\r\n .connect(serverUrl, username, password)\r\n .then(data => {\r\n this.$rootScope.$applyAsync((scope) => {\r\n this.$log.debug(\"ConnectionService.login success, profiles:\", data.profiles);\r\n this.profileModel.setProfiles(data.profiles);\r\n this.userLoggingIn = false;\r\n defer.resolve(data.profiles);\r\n });\r\n })\r\n .catch(error => {\r\n this.$rootScope.$applyAsync((scope) => {\r\n this.$log.error(\"Error calling client.connect: \", error);\r\n defer.reject(this.getUserErrorMessage(error));\r\n });\r\n });\r\n\r\n return defer.promise;\r\n }\r\n setProfile(username, password, profile) {\r\n const defer = this.$q.defer();\r\n\r\n if (!this.managementServerUrl) {\r\n defer.reject(\"must call 'ConnectionService.login' beforehand to set the server address\");\r\n }\r\n\r\n if(!password && this.currentUser) { // This is a reconnect scenario since the user has already logged in once\r\n username = this.currentUser.name;\r\n password = this.currentUser.password;\r\n }\r\n\r\n let setProfilePromise = null;\r\n\r\n if (this.sessionTimedOut) {\r\n setProfilePromise = this.client().connect(this.managementServerUrl, username, password, profile.profileId);\r\n }\r\n else {\r\n setProfilePromise = this.client().setProfile(username || \"\", password || \"\", profile.profileId);\r\n }\r\n\r\n this.awaitSPCActivity();\r\n\r\n setProfilePromise\r\n .then((data) => {\r\n this.$rootScope.$applyAsync((scope) => {\r\n this.setProfileSuccess(false, profile.profileId, data.channels, username, password, data.phoneLines, data.configInfo);\r\n this.mapLoaderService.setKeyFromProfileResponseAndCreateMapScriptNode(data);\r\n this.$log.debug(\"connectionService.setProfile success\", data);\r\n this.isReconnectCanceled = false; // Reset any existing reconnect state information\r\n defer.resolve();\r\n });\r\n })\r\n .catch(error => {\r\n this.$rootScope.$applyAsync((scope) => {\r\n this.$log.error(\"Error calling client.setProfile: \", error);\r\n defer.reject(this.getUserErrorMessage(error));\r\n });\r\n });\r\n\r\n return defer.promise;\r\n }\r\n\r\n setProfileSuccess(isReconnect, profileId, channels, userName, userPassword, phoneLines, configInfo) {\r\n\r\n this.profileModel.selectProfile(profileId, channels);\r\n this.setCurrentUser(userName, userPassword, this.managementServerUrl, profileId);\r\n this.$rootScope.$broadcast('ConnectionService.credentialsValidated', {\r\n reconnect: isReconnect,\r\n phoneLines: phoneLines,\r\n channels: channels\r\n });\r\n this.wtcpjsClientProviderService.setEndpointFilterThresholds(configInfo);\r\n }\r\n\r\n logout() {\r\n if (this.client().IsClientActive) {\r\n\r\n this.client().closeSession().then(() => {\r\n // Silence the audio player immediately (not required?)\r\n //this.client().AudioPlayerActive = false;\r\n this.$rootScope.$broadcast('ConnectionService.logout');\r\n });\r\n } else {\r\n this.$rootScope.$broadcast('ConnectionService.logout');\r\n }\r\n }\r\n\r\n getUserErrorMessage(err) {\r\n const errorCodes = {\r\n 1: \"There was an error\",\r\n 7: \"User name or password were invalid. Try again or contact your system administrator.\",\r\n 5: \"The management server license is invalid. Please contact your administrator.\",\r\n 23: \"You are already signed in from another client. Disconnect and try again\",\r\n 52: \"You must have at least one Profile to use WAVE. Please contact your administrator\"\r\n };\r\n\r\n if (err) {\r\n if (err.errorCode)\r\n return errorCodes[err.errorCode] || \"There was an error\";\r\n else\r\n return \"Library Error: \" + err;\r\n } else {\r\n return \"There was an error\";\r\n }\r\n }\r\n}\r\n\r\nangular\r\n .module('webcomm')\r\n .service('connectionService', [\r\n '$rootScope',\r\n '$q',\r\n '$location',\r\n '$log',\r\n '$timeout',\r\n 'wtcpjsClientProviderService',\r\n 'persistenceService',\r\n 'profileModel',\r\n 'authService',\r\n 'mapLoaderService',\r\n ConnectionService]);\r\n","class ContactService {\r\n constructor($rootScope, $q, $location, $log, $timeout, wtcpjsClientProviderService, anchorInfoService, endpointModel) {\r\n this.$rootScope = $rootScope;\r\n this.$q = $q;\r\n this.$log = $log;\r\n this.filterId = wtcpjsClientProviderService.filterTypes.addressBookFilter;\r\n this.getClient = wtcpjsClientProviderService.getClient;\r\n this.aiSvc = anchorInfoService;\r\n this.endpointModel = endpointModel;\r\n\r\n // TBD: When anchorInfo support is added to Proxy we should revisit the design of this service\r\n // We should cache results and bounds check the cache before fetching a new endpoints from\r\n // the address book filter. For now, we get everything so we will just leave it as a fire and forget\r\n\r\n $rootScope.$on('endpointModel.presenceUpdated', (e, channelEndpoints, channelId, endpointId, userName, filterIds) => {\r\n // This checks if presenceUpdated occurred because of channel activity (which only happens for the Self flagged user)\r\n // or if presenceUpdated occurred because of the endpoint channel filter has been updated\r\n let isMeOrChannelUser = (!filterIds || filterIds.indexOf(this.filterId) > -1);\r\n if (isMeOrChannelUser) {\r\n\r\n if (!channelEndpoints.has(endpointId)) { // Endpoint deleted\r\n $rootScope.$broadcast('contactService.contactOffline', endpointId, userName);\r\n } else {\r\n let endpoint = channelEndpoints.get(endpointId);\r\n if (endpoint.callAlias || endpoint.privateTxtEnabled) {\r\n let spcFlags = endpoint.flags.get(0);\r\n if(spcFlags) {\r\n if (spcFlags.Self) {\r\n $rootScope.$broadcast('contactService.selfUpdated', endpoint);\r\n } else {\r\n $rootScope.$broadcast('contactService.contactUpdated', endpoint);\r\n }\r\n }\r\n }\r\n }\r\n }\r\n });\r\n }\r\n\r\n getContacts(anchor) {\r\n var $q = this.$q;\r\n var $log = this.$log;\r\n var defer = this.$q.defer();\r\n var getClient = this.getClient;\r\n var endpointModel = this.endpointModel;\r\n var filterId = this.filterId;\r\n var index = 0;\r\n var matchIndx = 0;\r\n var data = [];\r\n var _myEndpoint = null;\r\n\r\n var getEndpointInfo = function(userName) {\r\n for (var x = matchIndx; x < data.length; x++) {\r\n if (data[x].userName === userName.toLowerCase()) {\r\n return data[matchIndx = x];\r\n }\r\n }\r\n return null;\r\n };\r\n\r\n // get anchor page only\r\n getClient()\r\n .setEndpointAddressBookFilter(filterId, { \"displayName\": \"*\" }, \"disposition;CallAlias;displayName;participantType\", 0,anchor)\r\n .then((resp) => {\r\n data = [];\r\n index = 0;\r\n _myEndpoint = endpointModel.getMyEndpoint();\r\n resp.endpointPropertyInfo.forEach((ep) => {\r\n if (ep.endpointInfo.endpointId === \"0\") {\r\n data[index++] = {\r\n userName: ep.endpointInfo.endpointName.toLowerCase(),\r\n name: ep.endpointProperties.displayName,\r\n type: ep.endpointProperties.participantType,\r\n isPresent: false,\r\n canP2P: ep.endpointProperties.participantType === 'RADIO' ? true : false,\r\n canTxt: false,\r\n endpoints: new Set(),\r\n callAlias: ep.endpointProperties.callAlias\r\n };\r\n } else if (!ep.endpointInfo.endpointFlags.Self &&\r\n ep.endpointInfo.endpointName !== _myEndpoint.userName) {\r\n var info = getEndpointInfo(ep.endpointInfo.endpointName);\r\n info.isPresent = true;\r\n // this isn' working, for some reason we get contacts before the phone line is active which makes no sense...\r\n info.canP2P = _myEndpoint.callAlias && ep.endpointProperties.disposition !== 'Phone'\r\n ? true\r\n : false;\r\n info.canTxt = ep.endpointProperties.privateTxtEnabled;\r\n info.endpoints.add(ep.endpointInfo.endpointId);\r\n let model = endpointModel.addEndpoint(0,\r\n ep.endpointInfo.endpointId,\r\n ep.endpointInfo.endpointName,\r\n ep.endpointInfo.endpointFlags);\r\n model.filterIds.push(filterId);\r\n }\r\n });\r\n defer.resolve({ totalContacts: resp.endpoints, data });\r\n }).catch((err) => {\r\n defer.reject(err);\r\n });\r\n\r\n return defer.promise;\r\n }\r\n} \r\n\r\nangular\r\n .module('webcomm')\r\n .service('contactService', [\r\n '$rootScope',\r\n '$q',\r\n '$location',\r\n '$log',\r\n '$timeout',\r\n 'wtcpjsClientProviderService',\r\n 'anchorInfoService',\r\n 'endpointModel',\r\n ContactService]);","angular\r\n .module('webcomm')\r\n .factory('dispositionService', [\r\n '$rootScope',\r\n '$log',\r\n 'wtcpjsClientProviderService',\r\n 'endpointModel',\r\n function (\r\n $rootScope,\r\n $log,\r\n wtcpjsClientProviderService,\r\n endpointModel) {\r\n\r\n // This service needs to be refactored to encapsulate known disposition states as well as track\r\n // disposition states for the user in a central place\r\n let service = {};\r\n let currentDisposition = '';\r\n\r\n let client = wtcpjsClientProviderService.getClient;\r\n\r\n service.setDisposition = function (endpointId, disposition) {\r\n client().setEndpointProperties(endpointId, {disposition}).then(() => {\r\n currentDisposition = disposition;\r\n $log.info(`set disposition endpoint property for endpointId ${endpointId} to ${disposition}`);\r\n $rootScope.$broadcast('dispositionService.dispositionSet', disposition);\r\n });\r\n }\r\n\r\n var unbindIsReconnecting = $rootScope.$on('isReconnecting', (e, reconnecting, newEPId) => {\r\n if(!reconnecting && newEPId) {\r\n if(currentDisposition === 'Phone') {\r\n currentDisposition = 'Ready';\r\n }\r\n\r\n if(currentDisposition) {\r\n $log.info('restoring disposition after reconnect');\r\n service.setDisposition(newEPId, currentDisposition);\r\n }\r\n }\r\n });\r\n\r\n $rootScope.$on('$destroy', () => {\r\n unbindIsReconnecting();\r\n });\r\n\r\n $log.debug('dispositionService initialized');\r\n return service;\r\n }\r\n ]);","class LocationService {\r\n constructor($rootScope, $timeout, $log, wtcpjsClientProviderService, endpointModel, settingsService, timeFormattingService) {\r\n var locSvc = this;\r\n\r\n this.$rootScope = $rootScope;\r\n this.$log = $log;\r\n this.settingsService = settingsService;\r\n this.timeFormattingService = timeFormattingService;\r\n this.sendGeoTimeout = null;\r\n this.sharingGeolocation = true;\r\n this.endpointModel = endpointModel;\r\n this.setTimeout = $timeout;\r\n this.clearTimeout = $timeout.cancel;\r\n this.sharingLocation = false;\r\n this.client = wtcpjsClientProviderService.getClient();\r\n this.loopFrequency = 300000; // 5 minutes\r\n this.loopCount = 0;\r\n\r\n function reset() {\r\n locSvc.clearTimeout(locSvc.sendGeoTimeout);\r\n locSvc.loopCount = 0;\r\n locSvc.sharingLocation = false;\r\n locSvc.sharingGeolocation = false;\r\n }\r\n\r\n $rootScope.$on(\"settingsService.shareLocation\", (e, isSharing) => {\r\n if (isSharing) {\r\n locSvc.shareLocation();\r\n }\r\n else {\r\n locSvc.stopSharingLocation();\r\n }\r\n });\r\n\r\n $rootScope.$on(\"ConnectionService.connectionClosed\", (e) => {\r\n locSvc.$log.debug(\"locationService: connectionClosed, resetting location service state\");\r\n reset();\r\n });\r\n\r\n $rootScope.$on(\"ConnectionService.logout\", (e) => {\r\n reset();\r\n });\r\n\r\n $log.info('Location Service initialized');\r\n }\r\n\r\n loopGeolocation(endpointId) {\r\n\r\n var locSvc = this;\r\n this.loopCount++;\r\n\r\n return new Promise(function(resolve, reject) {\r\n locSvc.sharingLocation = true;\r\n if(locSvc.sendGeoTimeout){\r\n locSvc.clearTimeout(locSvc.sendGeoTimeout);\r\n }\r\n locSvc.sendGeoTimeout = locSvc.setTimeout(() => { locSvc.loopGeolocation(endpointId); }, locSvc.loopFrequency);\r\n\r\n if (!locSvc.sharingGeolocation) {\r\n reject(\"geolocation not enabled\");\r\n }\r\n\r\n if (!locSvc.settingsService.location) {\r\n navigator.geolocation.getCurrentPosition(function(position) {\r\n let _lat = position.coords.latitude.toFixed(8);\r\n let _lng = position.coords.longitude.toFixed(8);\r\n locSvc.endpointModel.setLocation(endpointId, { 'lat': _lat, 'lng': _lng });\r\n\r\n if(locSvc.loopCount === 1) {\r\n locSvc.$rootScope.$broadcast(\"locationService.sharingLocation\", locSvc.endpointModel.getEndpoint(endpointId));\r\n }\r\n\r\n resolve(locSvc.sendGeolocation(endpointId, _lat, _lng));\r\n });\r\n } else {\r\n resolve(locSvc.sendGeolocation(endpointId, locSvc.settingsService.location.lat, locSvc.settingsService.location.lng));\r\n }\r\n });\r\n }\r\n\r\n sendGeolocation(endpointId, lat, long) {\r\n // If browser supports geolocation and option is enabled\r\n if (!lat || !long) {\r\n return this.client.setEndpointProperties(endpointId, {\r\n location: \"\"\r\n })\r\n .then((resp) => {\r\n this.$log.debug(\"Endpoint Location cleared\");\r\n return resp;\r\n })\r\n .catch((err) => {\r\n this.$log.error(\"There was an error trying to clear the location endpoint properity\");\r\n return err;\r\n });\r\n } else {\r\n let t = this.timeFormattingService.formatLocationDate(new Date());\r\n return this.client.setEndpointProperties(endpointId, {\r\n location: `t=${t},lo=${long},la=${lat}`\r\n })\r\n .then((resp) => {\r\n this.$log.debug(`Endpoint Location set: Time: ${t}, Latitude: ${lat}, Longitude: ${long} for Endpoint Id: ${endpointId}`);\r\n return resp;\r\n })\r\n .catch((err) => {\r\n this.$log.error('There was an error trying to set location endpoint properites', err);\r\n return err;\r\n });\r\n }\r\n }\r\n\r\n setLocation(lat, lng) {\r\n if (lat && lng) {\r\n this.settingsService.location = { lat, lng };\r\n this.clearTimeout(this.sendGeoTimeout);\r\n this.loopGeolocation(this.endpointModel.getMyEndpoint().id);\r\n } else\r\n this.settingsService.location = null;\r\n }\r\n\r\n shareLocation() {\r\n let locSvc = this;\r\n\r\n return new Promise(function(resolve, reject) {\r\n if (locSvc.sharingLocation) reject(\"error in locationService: you are already sharing location\");\r\n\r\n if (locSvc.settingsService.shareLocation) {\r\n if (locSvc.settingsService.location || \"geolocation\" in navigator) {\r\n locSvc.sharingGeolocation = true;\r\n var ep = locSvc.endpointModel.getMyEndpoint();\r\n locSvc.loopGeolocation(ep.id).then(function(p) {\r\n resolve(p);\r\n });\r\n } else {\r\n locSvc.settingsService.shareLocation = false;\r\n reject(\"Location has not been set by user and browser has disabled geolocation\");\r\n }\r\n } else {\r\n resolve(\"User not sharing location\");\r\n }\r\n });\r\n }\r\n\r\n stopSharingLocation() {\r\n this.loopCount = 0;\r\n this.sharingGeolocation = false;\r\n this.clearTimeout(this.sendGeoTimeout);\r\n this.sendGeolocation(this.endpointModel.getMyEndpoint().id);\r\n }\r\n\r\n get isSharingEnabled() {\r\n return this.settingsService.shareLocation;\r\n }\r\n}\r\n\r\nangular.module('webcomm').service('locationService',\r\n [\r\n '$rootScope',\r\n '$timeout',\r\n '$log',\r\n 'wtcpjsClientProviderService',\r\n 'endpointModel',\r\n 'settingsService',\r\n 'timeFormattingService',\r\n LocationService\r\n ]);","(function () {\r\n \"use strict\";\r\n\r\n angular\r\n .module(\"webcomm\")\r\n .config([\r\n \"$provide\", \"loggerProvider\", function($provide, loggerProvider) {\r\n // Use the `decorator` solution to substitute or attach behaviors to\r\n // original service instance; @see angular-mocks for more examples....\r\n let logProvier = loggerProvider.$get();\r\n let logLevel = getLoggingLevel();\r\n\r\n let loggingLevels = {\r\n none: [],\r\n error: ['error'], \r\n debug: ['debug', 'log', 'warn', 'error'], \r\n info: ['debug', 'log', 'warn', 'error', 'info'] \r\n };\r\n\r\n $provide.decorator('$log', [\r\n \"$delegate\", function($delegate) {\r\n let levels = ['debug', 'log', 'warn', 'info', 'error'];\r\n for (let level of levels)\r\n attach($delegate, level);\r\n\r\n return $delegate;\r\n }\r\n ]);\r\n\r\n function attach(log, level) {\r\n // Save the original $log['level']()\r\n\r\n var fn = log[level];\r\n //console.log(level, fn);\r\n\r\n if (isLevelEnabled(level)) {\r\n log[level] = function (...args) {\r\n let now = new Date();\r\n //args[0] = `${now} - ${args[0]}`;\r\n logProvier.log(level, now, ...args);\r\n fn(...args);\r\n };\r\n } else {\r\n log[level] = function() {} // do nothing :)\r\n }\r\n \r\n log[level].logs = []; // required for angularmocks\r\n }\r\n\r\n function isLevelEnabled(level) {\r\n let enabledLevels = loggingLevels[logLevel];\r\n return enabledLevels.indexOf(level) !== -1;\r\n }\r\n\r\n function getLoggingLevel() {\r\n // 'webcomm_logging_level' is a global - it comes directly from index.html \r\n return webcomm_logging_level === 'LOGGING_LEVEL_PLACEHOLDER' ? 'info' : webcomm_logging_level;\r\n }\r\n }\r\n ])\r\n .provider('logger', function() {\r\n let maxLogLength = 5000;\r\n let logMessages = [];\r\n //console.error(\"logger initialized\");\r\n\r\n this.$get = function() {\r\n return {\r\n log(level, date, ...args) {\r\n logMessages.push({ level, date, args });\r\n //console.info(\"log length: \" + logMessages.length);\r\n if (logMessages.length > maxLogLength)\r\n logMessages.shift();\r\n },\r\n\r\n get messages() {\r\n //console.info(\"getting log: \" + logMessages.length);\r\n return logMessages;\r\n }\r\n }\r\n }\r\n });\r\n\r\n})();","(function(angular) {\r\n var mapScript = null;\r\n\r\n class MapLoaderService {\r\n constructor($log) {\r\n this.log = $log;\r\n this.key = \"\";\r\n }\r\n\r\n get mapKey() {\r\n return this.key;\r\n }\r\n\r\n createMapScriptNode() {\r\n mapScript = document.createElement('script');\r\n mapScript.type = 'text/javascript';\r\n\r\n var googleMapScriptUrl = \"https://maps.googleapis.com/maps/api/js\";//&key=\" + data;\r\n if (this.mapKey)\r\n googleMapScriptUrl += \"?key=\" + this.mapKey;\r\n mapScript.setAttribute('src', googleMapScriptUrl);\r\n\r\n document.head.appendChild(mapScript);\r\n }\r\n\r\n destroyMapScriptNode() {\r\n if(mapScript) {\r\n window.google.maps = null;\r\n\r\n mapScript.parentNode.removeChild( mapScript );\r\n }\r\n }\r\n\r\n setKeyFromProfileResponseAndCreateMapScriptNode(data) {\r\n try {\r\n\r\n if(this.key && this.key !== data.configInfo.mapprovider.google.key) {\r\n this.destroyMapScriptNode();\r\n }\r\n\r\n this.key = data.configInfo.mapprovider.google.key;\r\n } catch (ex) {\r\n this.log.warn(\"MapKeyService::setKeyFromProfileResponse - failed to get key from configInfo.mapprovider.google.key of the setProfile response\")\r\n }\r\n\r\n if (this.key !== \"\") {\r\n this.log.info(\"Google Map API key provided by server: \" + this.key);\r\n } else this.log.warn(\"MapKeyService::setKeyFromProfileResponse - empty key in configInfo.mapprovider.google.key of the setProfile response\");\r\n\r\n if(!mapScript) {\r\n this.createMapScriptNode();\r\n }\r\n }\r\n }\r\n\r\n angular.module('webcomm').service('mapLoaderService', ['$log', MapLoaderService]);\r\n})(angular);","class MuteService {\r\n constructor($rootScope, $log, $timeout, wtcpjsClientProviderService, persistenceService) {\r\n this.$rootScope = $rootScope;\r\n this.$log = $log;\r\n this.$timeout = $timeout;\r\n this.clientFactory = wtcpjsClientProviderService.getClient;\r\n this.persistenceService = persistenceService;\r\n this.tempMuteChannels = [];\r\n \r\n // 'true' == muted\r\n this.channelMuteStatusMap = {};\r\n\r\n var onChannelsUpdated = $rootScope.$on('channelModel.channelsUpdated', (event, data) => this.updateChannels(data));\r\n var onActiveChannelsChanged = $rootScope.$on('wtcpjsService.activeChannelsChanged', (event, activeChannelList) => this.muteSavedChannels() );\r\n\r\n // unmute channel if PTT started on the channel\r\n var onPttStarted = $rootScope.$on('pttStarted', (event, channelId) => {\r\n if (this.getMuteStatus(channelId))\r\n this.toggleMute(channelId);\r\n });\r\n\r\n $rootScope.$on('$destroy', () => {\r\n onChannelsUpdated();\r\n onPttStarted();\r\n onActiveChannelsChanged();\r\n });\r\n }\r\n\r\n muteSavedChannels() {\r\n let savedMutedChannels = this.persistenceService.getUserProfileServerValue('mutedChannelIds');\r\n\r\n if(savedMutedChannels)\r\n for (let id of savedMutedChannels)\r\n this.channelMuteStatusMap[id] = true;\r\n\r\n var channels = this.getMutedChannels();\r\n\r\n if (channels.length > 0) {\r\n this._sendMutedChannelIds(channels).then(() => {\r\n this.$log.debug('Activating audio player, muted channels after reconnect', channels);\r\n this.$timeout(() => this.clientFactory().AudioPlayerActive = true, 500);\r\n });\r\n }\r\n else {\r\n this.$log.debug('Activating audio player, no muted channels');\r\n this.clientFactory().AudioPlayerActive = true;\r\n }\r\n }\r\n\r\n updateChannels(channels) {\r\n for (let channelId in channels) {\r\n if(channels.hasOwnProperty(channelId))\r\n this.channelMuteStatusMap[channelId] = false;\r\n }\r\n this.$log.debug(`updating mute status for channels - `, channels);\r\n }\r\n\r\n getMuteStatus(channelId) {\r\n if (channelId === undefined)\r\n return this.channelMuteStatusMap;\r\n else\r\n return this.channelMuteStatusMap[channelId];\r\n }\r\n\r\n toggleMute(channelId) {\r\n this.channelMuteStatusMap[channelId] = !this.channelMuteStatusMap[channelId];\r\n let mutedChannelIds = this.getMutedChannels();\r\n this._saveAndSendMutedChannel(mutedChannelIds);\r\n }\r\n\r\n getMutedChannels() {\r\n // grab the array of muted channel Ids\r\n return Object\r\n .keys(this.channelMuteStatusMap)\r\n .filter((x) => this.channelMuteStatusMap[x])\r\n .map((x) => parseInt(x));\r\n }\r\n \r\n tempMuteAll() {\r\n let mutedChannelIds = [];\r\n \r\n for (let channelId in this.channelMuteStatusMap) {\r\n if(!this.channelMuteStatusMap[channelId])\r\n this.tempMuteChannels.push(parseInt(channelId));\r\n \r\n mutedChannelIds.push(parseInt(channelId));\r\n this.channelMuteStatusMap[channelId] = true;\r\n }\r\n \r\n this.$log.debug(`mute un-muted channels - [${this.tempMuteChannels}]`);\r\n this._sendMutedChannelIds(mutedChannelIds);\r\n }\r\n \r\n restoreTempMute() {\r\n let mutedChannelIds = [];\r\n\r\n var indx = 0;\r\n for(let channelId in this.channelMuteStatusMap) {\r\n indx = this.tempMuteChannels.indexOf(parseInt(channelId));\r\n if(indx > -1) {\r\n this.channelMuteStatusMap[channelId] = false;\r\n } else\r\n mutedChannelIds.push(parseInt(channelId));\r\n }\r\n\r\n this.tempMuteChannels = [];\r\n\r\n this.$log.debug(`un-mute channels - [${this.tempMuteChannels}]`);\r\n this._sendMutedChannelIds(mutedChannelIds);\r\n }\r\n \r\n muteAll() {\r\n let mutedChannelIds = [];\r\n\r\n for (let channelId in this.channelMuteStatusMap) {\r\n mutedChannelIds.push(parseInt(channelId));\r\n this.channelMuteStatusMap[channelId] = true;\r\n }\r\n\r\n this._saveAndSendMutedChannel(mutedChannelIds);\r\n }\r\n\r\n unmuteAll() {\r\n for (let channelId in this.channelMuteStatusMap) {\r\n this.channelMuteStatusMap[channelId] = false;\r\n }\r\n\r\n this.$log.debug('unmute all');\r\n this._saveAndSendMutedChannel([]);\r\n }\r\n\r\n allChannelsMuted() {\r\n let keys = Object.keys(this.channelMuteStatusMap);\r\n if (keys.length === 0)\r\n return false;\r\n else\r\n return Object.keys(this.channelMuteStatusMap).every((id) => this.channelMuteStatusMap[id]);\r\n }\r\n\r\n _saveAndSendMutedChannel(mutedChannelIds) {\r\n this.persistenceService.setUserProfileServerValue('mutedChannelIds', mutedChannelIds);\r\n this._sendMutedChannelIds(mutedChannelIds);\r\n }\r\n\r\n _sendMutedChannelIds(mutedChannelIds) {\r\n this.$log.debug('muted channels: ' + mutedChannelIds);\r\n return this.clientFactory().muteChannels(mutedChannelIds);\r\n }\r\n}\r\n\r\nangular.module('webcomm').service('muteService', ['$rootScope', '$log', '$timeout', 'wtcpjsClientProviderService', 'persistenceService', MuteService]);","class NotificationService {\r\n constructor($rootScope, $log) {\r\n this._log = $log;\r\n this._rootScope = $rootScope;\r\n this._isApplicationActive = true;\r\n\r\n window.onfocus = () => this._isApplicationActive = true;\r\n window.onblur = () => this._isApplicationActive = false;\r\n\r\n this.init();\r\n this.bindHandlers();\r\n }\r\n\r\n init() {\r\n this._showNotifications = false;\r\n\r\n if (!(window.Notification && window.Notification.requestPermission())) {\r\n this._log.error(\"This browser does not support desktop notification\");\r\n } else {\r\n Notification.requestPermission().then((result) => {\r\n this._log.info(\"Notifications accepted\");\r\n this._showNotifications = true;\r\n });\r\n }\r\n }\r\n\r\n bindHandlers() {\r\n var unbindCallOfferReceived = this._rootScope.$on('privateCallService.callOfferReceived', (e, data) => {\r\n this.notifyIfInactive(\"WAVE: Incoming call from \" + data.callerInfo);\r\n });\r\n\r\n var unbindCallHangupReceived = this._rootScope.$on('privateCallService.callHangupReceived', (e, data) => {\r\n this.notifyIfInactive(\"WAVE: Call ended.\");\r\n });\r\n\r\n var unbindCallConnected = this._rootScope.$on('privateCallService.callConnected', (e, data) => {\r\n //this._log.warn(\"connected: data\", data);\r\n this.notifyIfInactive(\"WAVE: Call connected.\");\r\n });\r\n\r\n this._rootScope.$on('destroy', (e) => {\r\n unbindCallOfferReceived();\r\n unbindCallHangupReceived();\r\n unbindCallConnected();\r\n });\r\n }\r\n\r\n notifyIfInactive(message) {\r\n if (!this._isApplicationActive && this._showNotifications) {\r\n this._log.info(\"Sending notification message: \", message);\r\n let notification = new Notification(message);\r\n notification.onclick = () => window.focus(); // this might be redundant, but it seems to work in Linux. verify in Win/OSX\r\n }\r\n }\r\n}\r\n\r\nangular.module('webcomm').service('notificationService', ['$rootScope', '$log', NotificationService]);","class PersistenceService {\r\n constructor(localStorageService) {\r\n this.ROOTKEY = \"webcomm\";\r\n this.USERKEY = \"\";\r\n this.USERPROFILEKEY = \"\";\r\n this.USERPROFILESERVERKEY = \"\";\r\n this.localStorageService = localStorageService;\r\n this.isSupported = this.localStorageService.isSupported;\r\n\r\n if (!localStorageService.isSupported)\r\n throw Error(`Local Storage as it's configured is not supported (${localStorageService.getStorageType})`); // https://github.com/grevory/angular-local-storage\r\n }\r\n\r\n updateUserInfo(username, profileId, server) {\r\n this.USERKEY = `${this.ROOTKEY}.${username}`;\r\n this.USERPROFILEKEY = `${this.USERKEY}.${profileId}`;\r\n this.USERPROFILESERVERKEY = `${this.USERPROFILEKEY}.${server}`;\r\n }\r\n\r\n setAppValue(key, value) { this._set(this.ROOTKEY, key, value); }\r\n setUserValue(key, value) { this._set(this.USERKEY, key, value); }\r\n setUserProfileValue(key, value) { this._set(this.USERPROFILEKEY, key, value); }\r\n setUserProfileServerValue(key, value) { this._set(this.USERPROFILESERVERKEY, key, value); }\r\n\r\n getAppValue(key) { return this._get(this.ROOTKEY, key); }\r\n getUserValue(key) { return this._get(this.USERKEY, key); }\r\n getUserProfileValue(key) { return this._get(this.USERPROFILEKEY, key); }\r\n getUserProfileServerValue(key) { return this._get(this.USERPROFILESERVERKEY, key); }\r\n\r\n evictAppValue(key) { this._evict(this.ROOTKEY, key); }\r\n evictUserValue(key) { this._evict(this.USERKEY, key); }\r\n evictUserProfileValue(key) { this._evict(this.USERPROFILEKEY, key); }\r\n evictUserProfileServerValue(key) { this._evict(this.USERPROFILESERVERKEY, key); }\r\n\r\n _set(level, key, value) {\r\n let newKey = `${level}.${key}`;\r\n\r\n if (this._checkKeyExists(newKey))\r\n this._keyException(newKey);\r\n\r\n this.localStorageService.set(newKey, value);\r\n }\r\n\r\n _get(level, key) { return this.localStorageService.get(`${level}.${key}`); }\r\n\r\n _evict(level, key) { this.localStorageService.remove(`${level}.${key}`); }\r\n\r\n _checkKeyExists(key) {\r\n return (key === this.USERKEY || key === this.USERPROFILEKEY || key === this.USERPROFILESERVERKEY);\r\n }\r\n\r\n _keyException(key) {\r\n throw `key '${key}' is reserved for internal use by the application`;\r\n }\r\n}\r\n\r\nangular.module('webcomm').service('persistenceService', ['localStorageService', PersistenceService]);","(function(angular) {\r\n var _dispositionService;\r\n var _feedModel;\r\n var _channelModel;\r\n var _muteService;\r\n var _endpointModel;\r\n var _calls = {};\r\n\r\n function setPhoneDisposition(endpointId) {\r\n _dispositionService.setDisposition(endpointId, 'Phone');\r\n }\r\n\r\n function setReadyDisposition(endpointId) {\r\n _dispositionService.setDisposition(endpointId, 'Ready');\r\n }\r\n\r\n function endCall(call) {\r\n if (call) {\r\n let channel = _channelModel.getChannel(call.channelId);\r\n _feedModel.addChannelFeedEvent(call.channelId, '', 'call-ended', '');\r\n call.isActive = false;\r\n channel.callActive = false;\r\n _muteService.restoreTempMute();\r\n setReadyDisposition(_endpointModel.getMyEndpoint().id);\r\n }\r\n }\r\n\r\n class PrivateCallService {\r\n constructor(\r\n $rootScope,\r\n $q,\r\n $log,\r\n $timeout,\r\n wtcpjsClientProviderService,\r\n muteService,\r\n endpointModel,\r\n channelModel,\r\n feedModel,\r\n dispositionService,\r\n userService) {\r\n this.activationStatus = {'Pending': 1, 'Active': 2, 'Error': 3};\r\n this.$rootScope = $rootScope;\r\n this.$q = $q;\r\n this.$log = $log;\r\n _channelModel = channelModel;\r\n _endpointModel = endpointModel;\r\n _feedModel = feedModel;\r\n _muteService = muteService;\r\n _calls = {};\r\n this.client = wtcpjsClientProviderService.getClient();\r\n this.phoneLine = {status: 0, statusMessage: '', number: ''};\r\n this.activeCallOffer = null;\r\n this.activeCall = null;\r\n _dispositionService = dispositionService;\r\n\r\n var privateCallChannelFilterId = wtcpjsClientProviderService.filterTypes.privateCallChannelFilter;\r\n var spcFilterActive = false;\r\n\r\n this.numberCallIdMap = {};\r\n\r\n function notifyCallofferReceived(d) {\r\n $rootScope.$broadcast('privateCallService.callOfferReceived', d);\r\n }\r\n\r\n function isRadioUser(user) {\r\n return user.endpoints.length > 0 && user.endpoints[0].participantType === 'RADIO';\r\n }\r\n\r\n this.activeCallExists = () => {\r\n return this.activeCall && this.activeCall.isActive;\r\n };\r\n\r\n this.callOfferFromUserExists = (userName) => {\r\n return this.activeCallOffer && this.activeCallOffer.endpointPropertyInfo.endpointInfo.endpointName === userName;\r\n };\r\n\r\n /* Error states */\r\n this.noCallResource = false;\r\n this.invalidPhoneLine = false;\r\n\r\n this.createParticipantFilter = function (pcChan) {\r\n\r\n if (pcChan.participantId) {\r\n var myEndpoint = endpointModel.getMyEndpoint();\r\n let p1 = pcChan.participantId.replace('{', '\\\\{').replace('}', '\\\\}');\r\n let p2 = myEndpoint.userName.replace('{', '\\\\{').replace('}', '\\\\}');\r\n this.client.setEndpointSPCFilter(privateCallChannelFilterId, 0, {'userName': `^${p1}\\$|^${p2}\\$`}, \"*\", 0, new WtcpJs.AnchorInfo())\r\n .then((resp) => {\r\n spcFilterActive = true;\r\n $log.debug(\"private call endpoint callee retrieved\", resp);\r\n\r\n endpointModel.initializeEndpoints(pcChan.id, resp);\r\n\r\n /*this.client.setEndpointSPCFilter(privateCallChannelSelfFilterId, 0, {'userName': myEndpoint.userName}, '*', 0, new WtcpJs.AnchorInfo())\r\n .then((myResp) => {\r\n Array.prototype.push.apply(resp.endpointPropertyInfo, myResp.endpointPropertyInfo);\r\n endpointModel.initializeEndpoints(pcChan.id, resp);\r\n })\r\n .catch((err) => {\r\n $log.error(\"There was an error filtering on your endpoint\", err);\r\n });*/\r\n })\r\n .catch((err) => {\r\n $log.error(\"There was an error trying to retrieve the participant\", err);\r\n });\r\n }\r\n }\r\n\r\n this.privateCall = (callId, number) => {\r\n\r\n this.numberCallIdMap[number] = callId;\r\n return _calls[callId] = {callId, callAlias: number, isActive: true, channelId: 0};\r\n };\r\n\r\n var unbindChannelSelected = $rootScope.$on('channelModel.channelSelected', (e, channel) => {\r\n if (channel.id > 0 && spcFilterActive) {\r\n this.client.clearEndpointFilter(privateCallChannelFilterId)\r\n .then(() => {\r\n spcFilterActive = false;\r\n })\r\n .catch((err) => {\r\n $log.error('An error occurred while trying to clear the private call channel filter', err);\r\n });\r\n } else {\r\n this.createParticipantFilter(channel);\r\n }\r\n });\r\n\r\n var unbindLogout = $rootScope.$on('ConnectionService.logout', () => {\r\n _calls = {};\r\n this.numberCallIdMap = {};\r\n this.activeCall = null;\r\n spcFilterActive = false;\r\n });\r\n\r\n var unbindReconnect = $rootScope.$on('isReconnecting', (e, reconnect, epId) => {\r\n var c;\r\n if (reconnect) {\r\n channelModel.getActiveChannelIds().forEach((key) => {\r\n c = channelModel.getChannel(key);\r\n if (c.callActive) {\r\n c.callActive = false;\r\n feedModel.addChannelFeedEvent(this.activeCall.channelId, '', 'call-ended', '');\r\n this.activeCall.isActive = false;\r\n this.activeCall = null;\r\n }\r\n });\r\n\r\n _calls = {};\r\n this.numberCallIdMap = {};\r\n } else if(epId) {\r\n muteService.restoreTempMute();\r\n c = channelModel.getSelectedChannel();\r\n\r\n if(c && c.id < 0) {\r\n this.createParticipantFilter(c);\r\n } else {\r\n spcFilterActive = false;\r\n }\r\n }\r\n });\r\n\r\n var onPhoneLineStatusChanged = this.client.onPhoneLineStatusChanged.subscribe((d) => {\r\n let pcs = this;\r\n $rootScope.$applyAsync(function ($scope) {\r\n if (d.errorCode === 0) {\r\n pcs.phoneLine.status = pcs.activationStatus.Active;\r\n pcs.phoneLine.statusMessage = 'Ready';\r\n } else {\r\n pcs.phoneLine.status = pcs.activationStatus.Error;\r\n pcs.phoneLine.statusMessage = d.errorMessage;\r\n }\r\n });\r\n });\r\n\r\n var onCallProgressRecieved = this.client.onCallProgressReceived.subscribe((d) => {\r\n let pcs = this;\r\n $rootScope.$applyAsync(function () {\r\n $log.info('call progress received from Proxy', d);\r\n // CALL_STATE: 1 -> proceeding\r\n // 2 -> ringing\r\n // 3 -> connected\r\n\r\n if (d.callState === 3) {\r\n try {\r\n let channel = channelModel.getChannel(_calls[d.callId].channelId);\r\n\r\n if (!pcs.activeCallOffer) {\r\n // See TBD section of onCallOfferReceived for why this is necessary\r\n if(!channel.participantId) {\r\n if (!d.endpointPropertyInfo.endpointInfo.endpointName) {\r\n if (d.callerInfo) {\r\n channel.participantId = d.callerInfo;\r\n }\r\n } else {\r\n channel.participantId = d.endpointPropertyInfo.endpointInfo.endpointName;\r\n }\r\n }\r\n //pcs.endpointModel.addEndpointToChannel(_calls[d.callId].channelId, answeredByEP);\r\n } else {\r\n channel.participantId = pcs.activeCallOffer.endpointPropertyInfo.endpointInfo.endpointName;\r\n pcs.activeCallOffer = null; // Call is connected, clearing activeCallOffer\r\n }\r\n\r\n channel.callActive = true;\r\n\r\n pcs.createParticipantFilter(channel);\r\n feedModel.addChannelFeedEvent(channel.id, 'You', 'call-started', { message: 'Answered a call from '});\r\n $rootScope.$broadcast('privateCallService.callConnected', channel);\r\n } catch (ex) {\r\n $log.error(\"channel not found on call connected state: \" + ex);\r\n }\r\n }\r\n $rootScope.$broadcast('privateCallService.callProgressReceived', d);\r\n });\r\n });\r\n\r\n var onCallOfferReceived = this.client.onCallOfferReceived.subscribe((d) => {\r\n let pcs = this;\r\n pcs.activeCallOffer = d;\r\n $rootScope.$applyAsync(function () {\r\n // TBD: Revisit when Proxy/Clients fix this. Proxy does not normalize data for us so\r\n // when a private call comes from DR2, ADC, Radio we do not get any EndpointInfo. All\r\n // we have is the UserName in the callerInfo field. Fortunately that is all that we require\r\n if (d.endpointPropertyInfo.endpointInfo.endpointId.length === 0) {\r\n d.endpointPropertyInfo.endpointInfo.endpointName = d.callerInfo;\r\n\r\n let user = userService.getUser(d.callerInfo);\r\n if(user) {\r\n d.callerInfo = user.displayName;\r\n }\r\n\r\n // Auto-answering non thin client calls. These are treated as barge calls\r\n // and will be answered randomly by any client signed in with the same user\r\n if(!user || isRadioUser(user)) {\r\n pcs.callAnswer(true);\r\n } else { // It's ADC or DR2\r\n notifyCallofferReceived(d);\r\n }\r\n $log.debug('Non-thin-client Call Offer Received', d, user);\r\n } else {\r\n notifyCallofferReceived(d);\r\n }\r\n\r\n // Add an event for when you are receiving a call, even though you might not answer it\r\n feedModel.addChannelFeedEvent(0, d.callerInfo, 'call-offer', d);\r\n\r\n });\r\n });\r\n\r\n var onCallHangupReceived = this.client.onCallHangupReceived.subscribe((d) => {\r\n let pcs = this;\r\n $rootScope.$applyAsync(function ($scope) {\r\n $log.info('WebComm handling call hangup', d);\r\n let call = _calls[d.callId];\r\n endCall(call);\r\n /*if (call) {\r\n feedModel.addChannelFeedEvent(call.channelId, '', 'call-ended', '');\r\n call.isActive = false;\r\n channelModel.getChannel(call.channelId).callActive = false;\r\n pcs.muteService.restoreTempMute();\r\n setReadyDisposition(pcs.endpointModel.getMyEndpoint().id);\r\n }*/\r\n\r\n pcs.activeCallOffer = null;\r\n $rootScope.$broadcast('privateCallService.callHangupReceived', call);\r\n });\r\n });\r\n\r\n var onCallPTTOffReceived = this.client.onCallPTTOffReceived.subscribe((d) => {\r\n if(d.errorCode > 0) {\r\n $rootScope.$applyAsync(function ($scop) {\r\n let call = _calls[d.callId];\r\n $log.warn('Call PTT forced off', d.errorMessage);\r\n $rootScope.$broadcast('privateCallService.callPttOff', call);\r\n });\r\n }\r\n });\r\n\r\n $rootScope.$on('$destroy', () => {\r\n onCallHangupReceived();\r\n onCallOfferReceived();\r\n onCallProgressRecieved();\r\n onPhoneLineStatusChanged();\r\n onCallPTTOffReceived();\r\n unbindChannelSelected();\r\n unbindLogout();\r\n unbindReconnect();\r\n });\r\n\r\n $log.info(\"Private Call Service initialized\");\r\n }\r\n\r\n activatePhoneLine(line) {\r\n var pcs = this;\r\n\r\n if (!pcs.$rootScope.noMicrophone) {\r\n this.client.setEndpointPropertiesPrivateCallFilter(\"*\")\r\n .then((resp) => {\r\n this.client.setActivePhoneLines([line])\r\n .then((resp) => {\r\n pcs.phoneLine.number = line;\r\n pcs.phoneLine.status = pcs.activationStatus.Pending;\r\n pcs.phoneLine.statusMessage = 'Activating';\r\n })\r\n .catch((err) => {\r\n pcs.$log.error(err);\r\n\r\n switch (err.errorCode) {\r\n case 25:\r\n pcs.noCallResource = true;\r\n pcs.phoneLine.status = pcs.activationStatus.Error;\r\n pcs.phoneLine.statusMessage = 'No call resource';\r\n break;\r\n case 22:\r\n pcs.invalidPhoneLine = true;\r\n pcs.phoneLine.status = pcs.activationStatus.Error;\r\n pcs.phoneLine.statusMessage = 'Invalid phone line';\r\n break;\r\n }\r\n });\r\n });\r\n } else {\r\n pcs.$log.warn('Microphone not enabled, skipping phone line activation');\r\n }\r\n }\r\n\r\n getCall(callId) {\r\n return _calls[callId];\r\n }\r\n\r\n callRequest(contactNumber, contactUserName, contactName, barge) {\r\n this.$log.debug(`privateCallService.callRequest to contactNumber: ${contactNumber}, contactUserName: ${contactUserName}`);\r\n\r\n const pcs = this;\r\n\r\n // Someone is calling the client, but we are clicking to call a different user. Hangup on the active call\r\n // offer before placing call\r\n if(pcs.activeCallOffer) {\r\n this.callHangup(pcs.activeCallOffer.callId);\r\n }\r\n\r\n return pcs.$q(function (resolve, reject) {\r\n if (pcs.phoneLine.status === pcs.activationStatus.Active) {\r\n var callId = pcs.numberCallIdMap[contactNumber];\r\n var call = callId ? _calls[callId] : null;\r\n if (call && call.isActive) {\r\n reject('A call is already active, aborting');\r\n }\r\n else {\r\n // -- Defaults --\r\n var callType = 2;\r\n var myNumber = pcs.phoneLine.number;\r\n var myEndpoint = _endpointModel.getMyEndpoint();\r\n\r\n // -- Overrides --\r\n if (_endpointModel.getEndpoint(contactNumber)) {\r\n callType = 1;\r\n }\r\n\r\n if (callType === 1) {\r\n myNumber = myEndpoint.id;\r\n }\r\n\r\n pcs.client.makeCall(callType, pcs.phoneLine.number, contactNumber)\r\n .then((resp) => {\r\n call = new pcs.privateCall(resp.callId, resp.destination);\r\n call.channelId = _channelModel.addOrUpdatePrivateCallChannel(callType,\r\n myEndpoint.userName, contactUserName, contactNumber, contactName, resp.callId,\r\n contactUserName, barge);\r\n _muteService.tempMuteAll();\r\n _channelModel.selectChannel(call.channelId);\r\n pcs.activeCall = call;\r\n setPhoneDisposition(myEndpoint.id);\r\n resolve(call);\r\n })\r\n .catch((err) => {\r\n reject(err);\r\n });\r\n }\r\n } else {\r\n reject('Your phone line is not active');\r\n }\r\n });\r\n }\r\n\r\n callAnswer(barge) {\r\n const pcs = this;\r\n\r\n pcs.activeCall = null;\r\n\r\n return pcs.$q(function (resolve, reject) {\r\n if (pcs.phoneLine.status === pcs.activationStatus.Active) {\r\n pcs.client.answerCall(pcs.activeCallOffer.callId)\r\n .then((resp) => {\r\n let call = new pcs.privateCall(resp.callId, pcs.activeCallOffer.callerId);\r\n pcs.activeCall = call;\r\n let myEndpoint = _endpointModel.getMyEndpoint();\r\n let callerUserName = pcs.activeCallOffer.endpointPropertyInfo.endpointInfo.endpointName;\r\n call.channelId = _channelModel.addOrUpdatePrivateCallChannel(\r\n pcs.activeCallOffer.callType,\r\n myEndpoint.userName,\r\n callerUserName,\r\n pcs.activeCallOffer.callerId,\r\n pcs.activeCallOffer.callerInfo,\r\n resp.callId,\r\n callerUserName,\r\n barge);\r\n //pcs.endpointModel.addEndpointToChannel(call.channelId, myEndpoint);\r\n //pcs.endpointModel.addEndpointToChannel(call.channelId, callerEndpoint);\r\n _muteService.tempMuteAll();\r\n setPhoneDisposition(myEndpoint.id);\r\n resolve(call);\r\n })\r\n .catch((err) => {\r\n reject(err);\r\n });\r\n } else {\r\n reject('Your phone line is not active');\r\n }\r\n });\r\n }\r\n\r\n callHangup(callId) {\r\n const pcs = this;\r\n\r\n pcs.activeCall = null;\r\n return pcs.$q(function (resolve, reject) {\r\n if (pcs.phoneLine.status === pcs.activationStatus.Active) {\r\n pcs.client.hangupCall(callId)\r\n .then((resp) => {\r\n let call = _calls[resp.callId];\r\n endCall(call);\r\n /*if (call) {\r\n pcs.feedModel.addChannelFeedEvent(call.channelId, '', 'call-ended', '');\r\n call.isActive = false;\r\n _channelModel.getChannel(call.channelId).callActive = false;\r\n _muteService.restoreTempMute();\r\n setReadyDisposition(_endpointModel.getMyEndpoint().id);\r\n }*/\r\n\r\n pcs.$rootScope.$broadcast('privateCallService.callHangupReceived', call);\r\n resolve(resp);\r\n })\r\n .catch((err) => {\r\n reject(err);\r\n });\r\n } else {\r\n reject('Your phone line is not active');\r\n }\r\n });\r\n }\r\n }\r\n\r\n angular\r\n .module('webcomm')\r\n .service('privateCallService', [\r\n '$rootScope',\r\n '$q',\r\n '$log',\r\n '$timeout',\r\n 'wtcpjsClientProviderService',\r\n 'muteService',\r\n 'endpointModel',\r\n 'channelModel',\r\n 'feedModel',\r\n 'dispositionService',\r\n 'userService',\r\n PrivateCallService]);\r\n})(angular);","class PttService {\r\n constructor($rootScope, $q, $log, $timeout, wtcpjsClientProviderService, channelId, channelModel, endpointStatusService) {\r\n this.channelId = channelId;\r\n this.client = wtcpjsClientProviderService.getClient;\r\n this.$log = $log;\r\n this.$rootScope = $rootScope;\r\n this.$timeout = $timeout;\r\n this.$q = $q;\r\n this.channelModel = channelModel;\r\n this.endpointStatusService = endpointStatusService;\r\n this.pttState = 'off';\r\n this.pttRetryCnt = 0;\r\n }\r\n\r\n /* PUBLIC METHODS */\r\n pttStart() {\r\n let _this = this;\r\n if (this._pttInit()) {\r\n\r\n _this.client().PTTDown([_this.channelId])\r\n .then((data) => {\r\n _this.pttRetryCnt = 0;\r\n _this._notifyPttStarted();\r\n _this.$rootScope.$applyAsync(function () {\r\n if (data.channelResponses.length > 0 && _this.pttState === 'pending') {\r\n _this._processPttResponse(data.channelResponses[0], 'PTTDown');\r\n }\r\n });\r\n })\r\n .catch((err) => {\r\n if (err.errorCode !== 7001 || _this.pttRetryCnt === 3) {\r\n _this.pttRetryCnt = 0;\r\n _this._pttError('PTTDown', err);\r\n } else if (_this.pttState !== 'stopping') {\r\n _this.pttRetryCnt++;\r\n _this.$timeout(() => _this.pttStart(), 500);\r\n }\r\n });\r\n } else {\r\n this.pttStop();\r\n }\r\n }\r\n\r\n pttStop() {\r\n this.$log.debug('PTTService.pttStop started');\r\n if (this.isPttStarted()) {\r\n this.pttOffHandler && this.pttOffHandler();\r\n this._pttStopImplementation();\r\n this.$rootScope.$broadcast('pttStopped', this.channelId);\r\n }\r\n\r\n if (this.pttState === 'rejected') {\r\n this._stopped();\r\n }\r\n }\r\n\r\n callTooLong() {\r\n this.pttStop();\r\n this._pttError('CallPTTOff', 'PTT Too long');\r\n }\r\n\r\n isPttStarted() {\r\n return this.pttState === 'pending' || this.pttState === 'on';\r\n }\r\n\r\n isPttOn() {\r\n return this.pttState === 'on';\r\n }\r\n\r\n canTransmitAudio() {\r\n return this.client().WTCPAudioStatus.status === 'ready' &&\r\n this.channelModel.getChannel(this.channelId).canTransmitAudio;\r\n }\r\n\r\n isRxOnlyChannel() {\r\n return this.channelModel.getChannel(this.channelId).isRxOnlyChannel;\r\n }\r\n\r\n // images/icons/icon_ptt_{{status.getPttIconName()}}.png\r\n getPttIconName(isChannelSelected) {\r\n // Sync with other thin client(ios/android behavior) behavior\r\n // don't diable PTT button on simplex channel and someone else is speaking\r\n // If current user has an equal or lower priority than the speaker, I will be bonked out.\r\n\r\n //this.$log.info(`#${this.channelId} state: ${this.pttState}, isChannelSelected: ${isChannelSelected}`);\r\n switch (this.pttState) {\r\n case 'rejected': return 'bonk'; break;\r\n case 'pending': return 'requesting'; break;\r\n case 'stopping': return 'disabled'; break;\r\n case 'on': return !isChannelSelected; break; // returns 'true' or 'false'\r\n case 'off': return isChannelSelected; break;\r\n }\r\n }\r\n\r\n destroy() {\r\n //this.$log.debug(\"PttService.destroy for channel: #\" + this.channelId);\r\n if (this.pttOffHandler) {\r\n this.pttOffHandler();\r\n }\r\n }\r\n\r\n /* PRIVATE METHODS */\r\n _isSomeoneSpeakingOnSimplexChannel(channelId) {\r\n return this.channelModel &&\r\n this.channelModel.getChannel(channelId) &&\r\n this.channelModel.getChannel(channelId).isSimplex &&\r\n this.endpointStatusService.isAnyoneSpeakingOnChannel(channelId);\r\n }\r\n\r\n _notifyPttStarted() {\r\n this.$rootScope.$broadcast('pttStarted', this.channelId);\r\n }\r\n\r\n _pttInit() {\r\n\r\n if (this.pttState === 'stopping') { // do nothing\r\n this.$log.warn(\"tried to PTT while stopping\");\r\n return false;\r\n }\r\n\r\n this._pending();\r\n\r\n this.pttOffHandler = this.$rootScope.$on('wtcpjsService.pttOff', () => {\r\n this._playSound('error');\r\n this.pttStop();\r\n });\r\n\r\n return true;\r\n }\r\n\r\n _processPttResponse(response, pttType) {\r\n if (response.errorCode === 0 && response.errorMessage === 'OK') {\r\n this._enabled();\r\n } else {\r\n this.$log.debug(pttType + ' returned error', response);\r\n this._rejected(pttType);\r\n }\r\n }\r\n\r\n _pttError(pttType, err) {\r\n this.$log.error(pttType + ' exception', err);\r\n this._rejected(err);\r\n }\r\n\r\n _pttStopImplementation() {\r\n this.client().PTTUp()\r\n .then(() => {\r\n this.$log.info(\"Sucessfully received from PTTUp\");\r\n console.log(\"Successful PTTUp <-\");\r\n this._stopped(); \r\n })\r\n .catch((err) => { this._pttError('PTTUp', err);\r\n console.log(\"Reject PTTup <-\");\r\n }); \r\n this.$log.info(\"Start to stopping the PTTUP()->\");\r\n this._stopping();\r\n }\r\n\r\n\r\n _pending() {\r\n this.pttState = 'pending';\r\n this._playSound('trying');\r\n }\r\n\r\n _enabled() {\r\n this.pttState = 'on';\r\n this._playSound('grant');\r\n }\r\n\r\n _rejected(error) {\r\n this.pttState = 'rejected';\r\n this._playSound('error');\r\n if (!this.$rootScope.$$phase) {\r\n this.$rootScope.$apply();\r\n }\r\n this.$timeout(() => this._stopped(), 2000);\r\n }\r\n\r\n _stopped() {\r\n this.pttState = 'off';\r\n this.$log.debug('stopped PTT');\r\n }\r\n\r\n _stopping() {\r\n this.pttState = 'stopping';\r\n this.$log.debug('stopping PTT');\r\n }\r\n\r\n _playSound(soundFileName) {\r\n let src = `sounds/ptt_${soundFileName}.mp3`;\r\n let audio = new Audio(src);\r\n return new Promise((resolve, reject) => {\r\n let p = audio.play();\r\n if(p) {\r\n p\r\n .then(() => {\r\n var dur = (Math.ceil(audio.duration * 1000));\r\n setTimeout(resolve, dur);\r\n })\r\n .catch((err) => {\r\n reject(err);\r\n });\r\n } else {\r\n resolve();\r\n }\r\n });\r\n }\r\n}\r\n\r\nclass PrivateCallPttService extends PttService {\r\n constructor($rootScope, $q, $log, $timeout, wtcpjsClientProviderService, channelId, channelModel) {\r\n super($rootScope, $q, $log, $timeout, wtcpjsClientProviderService, channelId, channelModel);\r\n this.channel = this.channelModel.getChannel(channelId);\r\n }\r\n\r\n pttStart() {\r\n let _this = this;\r\n if (this._pttInit()) {\r\n\r\n _this.client().callPTTOn(_this.channel.callId).then((data) => {\r\n _this._notifyPttStarted();\r\n _this.$rootScope.$applyAsync(function () {\r\n if (_this.pttState === 'pending') {\r\n _this._processPttResponse(data, 'callPTTOn');\r\n }\r\n });\r\n }).catch((err) => _this._pttError('callPTTOn', err));\r\n } else {\r\n this.pttStop();\r\n }\r\n }\r\n\r\n _pttStopImplementation() {\r\n this.client().callPTTOff(this.channel.callId)\r\n .then(() => this._stopped())\r\n .catch((err) => { this._pttError('PTTUp', err); });\r\n this._stopping();\r\n }\r\n\r\n canTransmitAudio() {\r\n return this.client().WTCPAudioStatus.status === 'ready' && this.channel.callActive;\r\n }\r\n}\r\n\r\nangular\r\n .module('webcomm')\r\n .factory('pttService',\r\n ['$rootScope', '$q', '$log', '$timeout', 'wtcpjsClientProviderService', 'channelModel', 'endpointStatusService',\r\n function ($rootScope, $q, $log, $timeout, wtcpjsClientProviderService, channelModel, endpointStatusService) {\r\n return {\r\n create(channelId) {\r\n return new PttService($rootScope, $q, $log, $timeout, wtcpjsClientProviderService, channelId, channelModel, endpointStatusService);\r\n }\r\n };\r\n }])\r\n .factory('privateCallPttService',\r\n ['$rootScope', '$q', '$log', '$timeout', 'wtcpjsClientProviderService', 'channelModel', 'endpointStatusService',\r\n function ($rootScope, $q, $log, $timeout, wtcpjsClientProviderService, channelModel, endpointStatusService) {\r\n return {\r\n create(channelId) {\r\n return new PrivateCallPttService($rootScope, $q, $log, $timeout, wtcpjsClientProviderService, channelId, channelModel, endpointStatusService);\r\n }\r\n };\r\n }])","class RememberMeService {\r\n constructor(persistenceService) {\r\n this.KEY = \"rememberMe\";\r\n this.persistenceService = persistenceService;\r\n }\r\n\r\n isRemembered() {\r\n return this.get() ? true : false;\r\n }\r\n\r\n get() {\r\n return this.persistenceService.getAppValue(this.KEY);\r\n }\r\n\r\n remember(user, server, profile) {\r\n this.persistenceService.setAppValue(this.KEY, { user, server, profile });\r\n }\r\n\r\n forget() {\r\n this.persistenceService.evictAppValue(this.KEY);\r\n }\r\n}\r\n\r\nangular.module('webcomm').service('rememberMeService', ['persistenceService', RememberMeService]);","\"use strict\";\r\nclass SettingsService {\r\n constructor($rootScope, persistenceService) {\r\n this.rootScope = $rootScope;\r\n this.persistenceService = persistenceService;\r\n //this.getClient = wtcpjsClientProviderService.getClient;\r\n }\r\n\r\n persistVolume(percentScale) {\r\n this.persistenceService.setUserProfileServerValue('volume', { percentScale });\r\n }\r\n\r\n set shareLocation (value) {\r\n this.persistenceService.setUserProfileServerValue('shareLocation', value);\r\n this.rootScope.$broadcast('settingsService.shareLocation', value);\r\n }\r\n\r\n get shareLocation () {\r\n // Default\r\n let shareLoc = this.persistenceService.getUserProfileServerValue('shareLocation');\r\n if (typeof shareLoc !== \"boolean\") \r\n return this.shareLocation = true;\r\n else\r\n return shareLoc;\r\n }\r\n\r\n set location (value) {\r\n this.persistenceService.setUserProfileServerValue('location', value);\r\n }\r\n\r\n get location () {\r\n return this.persistenceService.getUserProfileServerValue('location');\r\n }\r\n\r\n getVolume() {\r\n let val = this.persistenceService.getUserProfileServerValue('volume');\r\n if (val)\r\n return val.percentScale;\r\n else\r\n return 100;\r\n }\r\n\r\n updateChannelSelection(channels) {\r\n this.persistenceService.setUserProfileServerValue('channels', channels);\r\n }\r\n\r\n getChannelSelection() {\r\n return this.persistenceService.getUserProfileServerValue('channels') || {};\r\n }\r\n}\r\n\r\nangular.module('webcomm').service('settingsService', ['$rootScope', 'persistenceService', SettingsService]);","angular\r\n .module('webcomm')\r\n .factory('textMessageService', [\r\n '$rootScope',\r\n '$log',\r\n 'wtcpjsClientProviderService',\r\n 'feedModel',\r\n 'channelModel',\r\n 'endpointModel',\r\n function (\r\n $rootScope,\r\n $log,\r\n wtcpjsClientProviderService,\r\n feedModel,\r\n channelModel,\r\n endpointModel) {\r\n const patterns = {\r\n url: /(?:(?:https?|ftp):\\/\\/)?(?:\\S+(?::\\S*)?@)?(?:(?!(?:10|127)(?:\\.\\d{1,3}){3})(?!(?:169\\.254|192\\.168)(?:\\.\\d{1,3}){2})(?!172\\.(?:1[6-9]|2\\d|3[0-1])(?:\\.\\d{1,3}){2})(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}(?:\\.(?:[1-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))|(?:(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)(?:\\.(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)*(?:\\.(?:[a-z\\u00a1-\\uffff]{2,}))\\.?)(?::\\d{2,5})?(?:[/?#]\\S*)?/gmi,\r\n webSocket: /^ws{1,2}:\\/\\//i\r\n };\r\n\r\n var unbindTextMessageHandler;\r\n var unbindPrivateMessageHandler;\r\n let service = {};\r\n let client = wtcpjsClientProviderService.getClient;\r\n let clientSentFeedIds = [];\r\n // tracks which dynamic channel ID is associated with which endpoint Id for PrivateCall Text Messages\r\n let p2pChannelMap = {};\r\n\r\n $rootScope.$on('channelModel.privateCallChannelAdded', function(e, d) {\r\n if(d.participantId) {\r\n p2pChannelMap[d.participantId] = d.id;\r\n }\r\n });\r\n\r\n $rootScope.$on('channelModel.channelsCleared', () => {\r\n p2pChannelMap = {};\r\n });\r\n\r\n $rootScope.$on('privateCallService.callConnected', (e, d) => {\r\n p2pChannelMap[d.participantId] = d.id;\r\n });\r\n\r\n $rootScope.$on('wtcpjsService.activeChannelsChanged', function(e, d) {\r\n setPrivateTxtCapableEndpointProp(endpointModel.getMyEndpoint().id);\r\n });\r\n\r\n $rootScope.$on('ConnectionService.login', function() {\r\n setMessageFilters();\r\n });\r\n\r\n $rootScope.$on('isReconnecting', (e, reconnecting) => {\r\n if (reconnecting) {\r\n if(unbindTextMessageHandler) {\r\n unbindTextMessageHandler();\r\n unbindTextMessageHandler = null;\r\n }\r\n\r\n if(unbindPrivateMessageHandler) {\r\n unbindPrivateMessageHandler();\r\n unbindPrivateMessageHandler = null;\r\n }\r\n }\r\n });\r\n\r\n function setMessageFilters() {\r\n if(unbindTextMessageHandler) {\r\n unbindTextMessageHandler();\r\n unbindTextMessageHandler = null;\r\n }\r\n\r\n if(unbindPrivateMessageHandler) {\r\n unbindPrivateMessageHandler();\r\n unbindPrivateMessageHandler = null;\r\n }\r\n\r\n client().setEndpointPropertiesTextMessageFilter(\"displayName;callAlias\")\r\n .then((resp) => {\r\n unbindTextMessageHandler = subscribeToTextMessageEvent();\r\n })\r\n .catch((err) => {\r\n $log.error('error setting text message EP Prop filter', err);\r\n });\r\n\r\n client().setEndpointPropertiesPrivateMessageFilter(\"displayName;callAlias\")\r\n .then(() => {\r\n unbindPrivateMessageHandler = subscribeToPrivateMediaMessageEvent();\r\n })\r\n .catch((err) => {\r\n $log.error('error setting private message EP Prop filter', err);\r\n });\r\n }\r\n\r\n // Workaround until client capabilities work is complete\r\n function setPrivateTxtCapableEndpointProp(endpointId) {\r\n client().setEndpointProperties(endpointId, {privateTxtEnabled: true}).then(() => {\r\n $log.info(`set privateTxtEnabled endpoint property for endpointId ${endpointId}`);\r\n });\r\n }\r\n\r\n function lookForUrls(data) {\r\n /* --- text message parsing rule section for message enrichment --- */\r\n /* --- should make this more robust and support linkifying urls even in message bodies --- */\r\n\r\n var mIndx = 0, m;\r\n\r\n data.urls = [];\r\n\r\n while ((m = patterns.url.exec(data.message))) {\r\n data.urls[mIndx++] = { index: m.index, value: m[0] };\r\n }\r\n }\r\n\r\n function generateFeedEvent(id, data) {\r\n\r\n lookForUrls(data);\r\n let newEvent = feedModel.addChannelFeedEvent(id, data.properties.displayName, \"text-message\", data);\r\n return newEvent.feedId;\r\n }\r\n\r\n function subscribeToTextMessageEvent() {\r\n return client().onTextMessageReceived.subscribe(function(data) {\r\n $rootScope.$applyAsync(function () {\r\n var id = data.destinationChannelId;\r\n var myEndpoint = endpointModel.getMyEndpoint();\r\n data.sameEndpoint = myEndpoint.id === data.sourceEndpointId;\r\n data.Self = myEndpoint.userName === data.sourceUserName;\r\n var feedId;\r\n\r\n if (!data.sameEndpoint) {\r\n feedId = generateFeedEvent(id, data);\r\n } else {\r\n feedId = clientSentFeedIds.shift();\r\n }\r\n\r\n $log.debug(\"OnTextMessageReceived: \", data);\r\n\r\n $rootScope.$broadcast('textMessageService.textMessageComplete', feedId);\r\n });\r\n });\r\n }\r\n\r\n function subscribeToPrivateMediaMessageEvent() {\r\n return client().onPrivateMediaMessageReceived.subscribe(function(data) {\r\n $rootScope.$applyAsync(function () {\r\n var myEndpoint = endpointModel.getMyEndpoint();\r\n // This data has changed, will need to revise\r\n data.Self = myEndpoint.userName === data.sourceUserName;\r\n data.message = data.messageData.data;\r\n\r\n var destination = data.Self ? data.messageData.participants.find((p) => p.userName !== myEndpoint.userName) : null;\r\n\r\n var callAlias = data.Self ? destination.callAlias : data.properties.callAlias;\r\n var displayName = data.Self ? destination.displayName : data.properties.displayName;\r\n var participantId = data.Self ? destination.userName : data.sourceUserName;\r\n\r\n var id = (p2pChannelMap[data.sourceUserName] || (p2pChannelMap[data.sourceUserName] = (channelModel.addOrUpdatePrivateCallChannel(\r\n 2,\r\n myEndpoint.userName,\r\n participantId,\r\n callAlias,\r\n displayName,\r\n null,\r\n participantId))));\r\n\r\n //channelModel.selectChannel(id);\r\n\r\n var feedId = generateFeedEvent(id, data);\r\n\r\n $log.debug(\"OnPrivateMediaMessageReceived: \", data);\r\n\r\n $rootScope.$broadcast('textMessageService.textMessageComplete', feedId);\r\n });\r\n });\r\n }\r\n \r\n function getTxtData(channel, endpoint, message, isAlert) {\r\n return {\r\n Self: true,\r\n destinationChannelId: channel.id,\r\n important: isAlert || false,\r\n message: message,\r\n name: endpoint.name\r\n };\r\n }\r\n\r\n function sendMessage(targetEndpoint, myEndpoint, channel, message, feedId, conversationId, isAlert) {\r\n var txtData = getTxtData(channel, myEndpoint, message, isAlert);\r\n var msg = {};\r\n\r\n if (!feedId) {\r\n lookForUrls(txtData);\r\n msg = feedModel.addChannelFeedEvent(channel.id, myEndpoint.name, 'text-message', txtData);\r\n msg.clientTime = 'sending...';\r\n clientSentFeedIds.push(msg.feedId);\r\n }\r\n\r\n var p2pMessage = new WtcpJs.PrivateTextMessageRequest({conversationId});\r\n p2pMessage.data = message;\r\n p2pMessage.participants.push(targetEndpoint.userName);\r\n p2pMessage.participants.push(myEndpoint.userName);\r\n p2pMessage.Label = `Conversation with ${myEndpoint.name}`;\r\n\r\n return client().sendP2PMessage(p2pMessage, {important: txtData.important})\r\n .then((resp) => {\r\n if (resp.errorCode === 0) {\r\n msg.confirmed = true;\r\n msg.clientTime = resp.textMsgConfirmedDate;\r\n return msg.feedId;\r\n } else {\r\n throw new Error(resp.errorMessage);\r\n }\r\n })\r\n .catch((err) => {\r\n $log.error(\"there was an error sending private text message\", err);\r\n throw {feedId: msg.feedId, errorMessage: err.errorMessage};\r\n });\r\n }\r\n\r\n service.sendPrivateTextMessage = function ( channel, targetEndpoint, myEndpoint, message, feedId, isAlert) {\r\n\r\n return sendMessage(targetEndpoint, myEndpoint, channel, message, feedId, null, isAlert);\r\n };\r\n\r\n service.sendTextMessage = function (channel, endpoint, message, feedId, isAlert) {\r\n if (!endpoint) {\r\n return false;\r\n }\r\n\r\n let txtData = getTxtData(channel, endpoint, message, isAlert);\r\n\r\n let msg = {};\r\n\r\n if (!feedId) {\r\n lookForUrls(txtData);\r\n msg = feedModel.addChannelFeedEvent(channel.id, endpoint.name, 'text-message', txtData);\r\n msg.clientTime = 'sending...';\r\n }\r\n\r\n return client().sendTextMessage(channel.id, message, {important: txtData.important})\r\n .then((resp) => {\r\n if (resp.errorCode === 0) {\r\n msg.confirmed = true;\r\n msg.clientTime = resp.textMsgConfirmedDate;\r\n clientSentFeedIds.push(msg.feedId);\r\n return msg.feedId;\r\n } else {\r\n throw new Error(resp.errorMessage);\r\n }\r\n })\r\n .catch((err) => {\r\n throw {feedId: msg.feedId, errorMessage: err.errorMessage};\r\n });\r\n }\r\n\r\n /* --- Initializations --- */\r\n\r\n setMessageFilters();\r\n\r\n // TBD: Remove once private messaging is working\r\n //setPrivateTxtCapableEndpointProp(endpointModel.getMyEndpoint().id);\r\n\r\n $log.debug('textMessageService initialized');\r\n return service;\r\n }]);","angular\r\n .module('webcomm')\r\n .factory('timeFormattingService', function () {\r\n return {\r\n formatFeedDate: function (date) {\r\n if (!(date instanceof Date))\r\n throw \"date must be a Date object\";\r\n\r\n var hours = date.getHours();\r\n var minutes = date.getMinutes();\r\n var ampm = hours >= 12 ? 'pm' : 'am';\r\n hours = hours % 12;\r\n hours = hours ? hours : 12; // the hour '0' should be '12'\r\n minutes = minutes < 10 ? '0' + minutes : minutes;\r\n var strTime = hours + ':' + minutes + ampm;\r\n\r\n var days = [\"Sun\",\"Mon\",\"Tue\",\"Wed\",\"Thur\",\"Fri\",\"Sat\"];\r\n \r\n return days[date.getDay()] + ' ' + strTime;\r\n },\r\n \r\n formatLocationDate: function(fromDate) {\r\n let year = fromDate.getUTCFullYear();\r\n // note : getUTCMonth 0(Jan)-11(Dec)\r\n let month = fromDate.getUTCMonth() < 9 ? '0' + (fromDate.getUTCMonth()+1) : fromDate.getUTCMonth()+1;\r\n let day = fromDate.getUTCDate() < 10 ? '0' + fromDate.getUTCDate() : fromDate.getUTCDate(); \r\n let hour = fromDate.getUTCHours() < 10 ? '0' + fromDate.getUTCHours() : fromDate.getUTCHours(); \r\n let minute = fromDate.getUTCMinutes() < 10 ? '0' + fromDate.getUTCMinutes() : fromDate.getUTCMinutes(); \r\n let second = fromDate.getUTCSeconds() < 10 ? '0' + fromDate.getUTCSeconds() : fromDate.getUTCSeconds();\r\n return `${year}${month}${day}${hour}${minute}${second}`;\r\n }\r\n }\r\n });","class TupleDictionaryService {\r\n constructor($rootScope, $log) {\r\n this.$scope = $rootScope;\r\n this.$log = $log;\r\n this.dict = {} ;\r\n };\r\n\r\n tupleToString(tuple) {\r\n return tuple.join(\",\");\r\n }\r\n\r\n init() { \r\n this.dict = {};\r\n }\r\n \r\n put(tuple, value) {\r\n this.dict[this.tupleToString(tuple)] = value;\r\n }\r\n\r\n get(tuple) {\r\n return this.dict[this.tupleToString(tuple)];\r\n }\r\n\r\n remove(tuple) {\r\n delete this.dict[this.tupleToString(tuple)];\r\n }\r\n\r\n};\r\n\r\nangular.module('webcomm').service('tupleDictionaryService', ['$rootScope', '$log', TupleDictionaryService]);\r\n","(function(angular) {\r\n\r\n var _provider;\r\n var _endpointModel;\r\n var _userService = {};\r\n var _dispositionService;\r\n var _channelId;\r\n var _cm;\r\n var _log;\r\n var _channelUsersMap;\r\n var _users = [];\r\n var _rootScope;\r\n var _activeDispositionEP;\r\n\r\n function findIndexOfUser(user) {\r\n return _users.findIndex((val) => {\r\n return val.userName === user;\r\n });\r\n }\r\n\r\n function findIndexOfEndpoint(user, epId) {\r\n return user.endpoints.findIndex((ep) => {\r\n return ep.id === epId;\r\n });\r\n }\r\n\r\n function sameUserDiffEndpoint(ep1, ep2) {\r\n return ep1.userName === ep2.userName && ep1.id !== ep2.id\r\n }\r\n\r\n function addUserToCollection(user) {\r\n var ui = new _userService.UserInfo(user);\r\n\r\n try {\r\n ui.endpoints = Array.from(_channelUsersMap.get(user).values());\r\n for (let ep of ui.endpoints) {\r\n ui.updateUserInfo(ep);\r\n }\r\n\r\n _users.push(ui);\r\n } catch(exc) {\r\n _log.error('userService error:', exc);\r\n }\r\n\r\n return ui;\r\n }\r\n\r\n function updateMyDisposition(ep) {\r\n var _myEndpoint = _endpointModel.getMyEndpoint();\r\n\r\n if (!ep.Self && (_myEndpoint && ep.userName === _myEndpoint.userName)) {\r\n if (_myEndpoint.disposition !== ep.disposition) {\r\n _dispositionService.setDisposition(_myEndpoint.id, ep.disposition);\r\n }\r\n }\r\n\r\n }\r\n\r\n function isPrivateTextEnabled(endpoint) {\r\n return !endpoint.Self && endpoint.userName !== _endpointModel.getMyEndpoint().userName; // && endpoint.privateTxtEnabled === 'true';\r\n }\r\n\r\n (function(module) {\r\n\r\n function isBusy(endpoint) {\r\n return endpoint.disposition && endpoint.disposition.match(/^busy$/i) !== null;\r\n }\r\n\r\n function isOnPhone(endpoint) {\r\n return endpoint.disposition && endpoint.disposition.match(/^phone$/i) !== null;\r\n }\r\n\r\n function isAway(endpoint) {\r\n return endpoint.disposition && endpoint.disposition.match(/^away$/i) !== null;\r\n }\r\n\r\n function privateCallEnabled(endpoint) {\r\n\r\n if (!endpoint.Self && endpoint.name !== _endpointModel.getMyEndpoint().name && endpoint.callAlias) {\r\n return true;\r\n }\r\n\r\n return false;\r\n }\r\n\r\n class UserInfo {\r\n\r\n constructor(userName) {\r\n this.userName = userName;\r\n this.displayName = '';\r\n this.endpoints = [];\r\n this._endpointIndex = 0;\r\n this.sharingLocation = false;\r\n this.privateCallEnabled = false;\r\n this.privateTextEnabled = false;\r\n this.callAlias = '';\r\n this.self = false;\r\n this.callActive = false;\r\n }\r\n\r\n get endpointIndex() {\r\n return this._endpointIndex;\r\n }\r\n\r\n set endpointIndex(val) {\r\n if (val > (this.endpoints.length - 1)) {\r\n this._endpointIndex = 0;\r\n } else {\r\n this._endpointIndex = val;\r\n }\r\n }\r\n\r\n get name() {\r\n return this.getCurrentEndpoint().name;\r\n }\r\n\r\n endpointExists(endpointId) {\r\n return findIndexOfEndpoint(this, endpointId) > -1;\r\n }\r\n\r\n addEndpoint(ep) {\r\n this.endpoints.push(ep);\r\n this.updateUserInfo(ep);\r\n }\r\n\r\n deleteEndpoint(endpointId) {\r\n var epIndex = findIndexOfEndpoint(this, endpointId);\r\n if(epIndex > -1) {\r\n var deleted = this.endpoints.splice(epIndex, 1);\r\n var _myEndpoint = _endpointModel.getMyEndpoint();\r\n this.endpointIndex = 0;\r\n\r\n if (deleted.length > 0) {\r\n var sharingEP = this.endpoints.find((ep) => {\r\n return ep.privateTxtEnabled && ep.privateTxtEnabled === 'true' && ep.userName !== _myEndpoint.userName;\r\n });\r\n if (!sharingEP) {\r\n\r\n this.privateTextEnabled = false;\r\n _rootScope.$broadcast('userService.privateTextEnabled', this, false);\r\n }\r\n }\r\n }\r\n }\r\n\r\n updateUserInfo(ep) {\r\n var _myEndpoint = _endpointModel.getMyEndpoint();\r\n\r\n let indx = findIndexOfEndpoint(this, ep.id);\r\n\r\n if (indx > -1) {\r\n this.endpoints[indx] = ep;\r\n }\r\n\r\n if (ep.userName === _myEndpoint.userName) {\r\n this.self = true;\r\n }\r\n\r\n var _privateCallEnabled = !isBusy(ep) && !isOnPhone(ep) && ( this.privateCallEnabled || privateCallEnabled(ep) );\r\n\r\n if (ep.location) {\r\n this.sharingLocation = true;\r\n }\r\n\r\n this.displayName = this.displayName || ep.name;\r\n\r\n this.callAlias = ep.callAlias;\r\n\r\n if (!this.callActive) {\r\n this.privateCallEnabled = _privateCallEnabled;\r\n }\r\n\r\n if (isPrivateTextEnabled(ep)) {\r\n if (!this.privateTextEnabled) {\r\n this.privateTextEnabled = true;\r\n _rootScope.$broadcast('userService.privateTextEnabled', this, true);\r\n }\r\n }\r\n\r\n // Disposition\r\n\r\n var _disposition = '';\r\n\r\n if (ep.disposition) {\r\n _disposition = ep.disposition.toLowerCase();\r\n }\r\n\r\n switch (_disposition) {\r\n case \"ready\":\r\n // When first logging in, endpoint disposition is Ready. But we don't know if the user\r\n // actually is in a Ready state. We need to look at all other endpoints of this user\r\n // and see if they are on the phone or busy\r\n if(ep.Self) {\r\n if (!_activeDispositionEP) {\r\n _activeDispositionEP = this.endpoints.find(isOnPhone);\r\n }\r\n\r\n if (_activeDispositionEP && _activeDispositionEP.id !== ep.id) { // User not 'ready'\r\n updateMyDisposition(_activeDispositionEP);\r\n _disposition = ep.disposition.toLowerCase();\r\n }\r\n }\r\n\r\n if(_activeDispositionEP && _activeDispositionEP.id === ep.id) {\r\n updateMyDisposition(ep);\r\n _activeDispositionEP = void 0;\r\n }\r\n\r\n if(!_activeDispositionEP || !sameUserDiffEndpoint(_activeDispositionEP, ep)) {\r\n this.disposition = _disposition;\r\n }\r\n\r\n break;\r\n case \"phone\":\r\n if(!_activeDispositionEP && sameUserDiffEndpoint(_myEndpoint, ep) && !this.callActive) {\r\n _activeDispositionEP = ep;\r\n }\r\n\r\n updateMyDisposition(ep);\r\n this.disposition = _disposition;\r\n\r\n break;\r\n case \"busy\":\r\n case \"away\":\r\n\r\n updateMyDisposition(ep);\r\n this.disposition = _disposition;\r\n\r\n break;\r\n case \"idle\":\r\n let allIdle = true;\r\n\r\n for (var x = 0; x < this.endpoints.length; x++) {\r\n if (this.endpoints[x].disposition !== ep.disposition) {\r\n allIdle = false;\r\n break;\r\n }\r\n }\r\n\r\n if (allIdle) {\r\n this.disposition = _disposition;\r\n }\r\n break;\r\n }\r\n }\r\n\r\n getCurrentEndpoint() {\r\n return this.endpoints[this.endpointIndex];\r\n }\r\n\r\n getNextEndpoint() {\r\n this.endpointIndex++;\r\n return this.getCurrentEndpoint();\r\n }\r\n\r\n get location() {\r\n if (!this.sharingLocation) return void 0;\r\n\r\n let _curEndpoint = this.getCurrentEndpoint();\r\n\r\n if(_curEndpoint && _curEndpoint.location) {\r\n return _curEndpoint.location;\r\n } else {\r\n if(!_curEndpoint) {\r\n _log.warn(\"Current Endpoint is undefined, this shouldn't happen\");\r\n }\r\n return this.getNextLocation();\r\n }\r\n }\r\n getNextLocation() {\r\n var startIndex = ++this.endpointIndex;\r\n var ep = this.getCurrentEndpoint();\r\n while (ep && !ep.location) {\r\n ep = this.getNextEndpoint();\r\n\r\n if (this.endpoints.length === 1 || this.endpointIndex === startIndex) {\r\n _log.warn(\"user is sharingLocation but no endpoint has location data\");\r\n this.sharingLocation = false;\r\n return void 0;\r\n }\r\n }\r\n\r\n if(ep) {\r\n return ep.location;\r\n } else {\r\n _log.warn(\"ep is undefined, this should never happen\");\r\n return void 0;\r\n }\r\n }\r\n }\r\n\r\n module.UserInfo = UserInfo;\r\n })(_userService);\r\n\r\n class UserService {\r\n constructor($rootScope, $log, wtcpjsClientProviderService, channelModel, endpointModel, dispositionService) {\r\n var unbindUserJoined = null;\r\n _cm = channelModel;\r\n _log = $log;\r\n _channelUsersMap = new Map();\r\n _dispositionService = dispositionService;\r\n _endpointModel = endpointModel;\r\n _rootScope = $rootScope;\r\n _provider = wtcpjsClientProviderService;\r\n\r\n function unbindExistingUserJoinedHandler() {\r\n if(unbindUserJoined) {\r\n unbindUserJoined();\r\n }\r\n }\r\n\r\n function clearUsers() {\r\n _users.length = 0;\r\n _channelUsersMap.clear();\r\n _channelId = 0;\r\n unbindExistingUserJoinedHandler();\r\n }\r\n\r\n function loadUsers() {\r\n _users.length = 0;\r\n _channelId = channelModel.getSelectedChannel().id;\r\n _channelUsersMap = endpointModel.getChannelUsers(_channelId);\r\n\r\n for (let user of _channelUsersMap.keys()) {\r\n addUserToCollection(user);\r\n }\r\n\r\n unbindExistingUserJoinedHandler();\r\n unbindUserJoined = $rootScope.$on('endpointModel.userJoined', function(event, channelId, endpoint) {\r\n var selectedChannel = _cm.getSelectedChannel();\r\n //var isPrivateCallFilter = endpoint.filterIds && endpoint.filterIds.includes(_provider.filterTypes.privateCallChannelFilter);\r\n if( selectedChannel && channelId === selectedChannel.id ) {\r\n $rootScope.$broadcast('userService.userJoined', addUserToCollection(endpoint.userName));\r\n }\r\n });\r\n\r\n $rootScope.$broadcast('userService.usersLoaded', _users);\r\n }\r\n\r\n function isSelectedChannel(channelId) {\r\n var selectedChannel = channelModel.getSelectedChannel();\r\n\r\n return selectedChannel && channelId === selectedChannel.id;\r\n }\r\n\r\n function userOnSelectedChannel(channelId) {\r\n let _selectedChannel = _cm.getSelectedChannel();\r\n\r\n if(!_selectedChannel) {\r\n return false;\r\n }\r\n\r\n if (channelId === 0) {\r\n return _selectedChannel.id < 0;\r\n } else {\r\n return channelId === _selectedChannel.id;\r\n }\r\n }\r\n\r\n var unbindUserLeft = $rootScope.$on('endpointModel.userLeft', (event, channelId, userName) => {\r\n if(userOnSelectedChannel(channelId)) {\r\n var userIndex = findIndexOfUser(userName);\r\n\r\n if (userIndex > -1) {\r\n $rootScope.$broadcast('userService.userLeft', _users.splice(userIndex, 1)[0], channelId);\r\n }\r\n }\r\n });\r\n\r\n var unbindEndpointLogout = $rootScope.$on('ConnectionService.logout', () => {\r\n clearUsers();\r\n });\r\n\r\n var unbindEndpointsLoaded = $rootScope.$on('endpointModel.endpointsLoaded', () => {\r\n loadUsers();\r\n });\r\n\r\n var unbindPresenceUpdated = $rootScope.$on('endpointModel.presenceUpdated', (event, channelEndpoints, channelId, endpointId, userName) => {\r\n\r\n if (isSelectedChannel(channelId)){\r\n\r\n var userIndex = findIndexOfUser(userName);\r\n\r\n if(userIndex > -1) {\r\n var user = _users[userIndex];\r\n\r\n if (channelEndpoints.has(endpointId)) {\r\n var updatedEP = endpointModel.getEndpoint(endpointId);\r\n\r\n _channelUsersMap.get(userName).set(endpointId, updatedEP);\r\n if (user.endpointExists(endpointId)) {\r\n user.updateUserInfo(updatedEP);\r\n } else {\r\n user.addEndpoint(updatedEP);\r\n }\r\n\r\n $rootScope.$broadcast('userService.userUpdated', _users[userIndex]);\r\n } else { // Endpoint has left\r\n user.deleteEndpoint(endpointId);\r\n }\r\n }\r\n }\r\n });\r\n\r\n var unbindCallConnected = $rootScope.$on('privateCallService.callConnected', (e, channel) => {\r\n var userIndex = findIndexOfUser(channel.participantId);\r\n\r\n if(userIndex > -1) {\r\n let user = _users[userIndex];\r\n user.callActive = true;\r\n _activeDispositionEP = _endpointModel.getMyEndpoint();\r\n user.privateCallEnabled = false;\r\n }\r\n });\r\n\r\n var unbindReconnecting = $rootScope.$on('isReconnecting', (e, reconnecting) => {\r\n if(reconnecting) {\r\n _activeDispositionEP = null;\r\n }\r\n });\r\n\r\n $rootScope.$on('destroy', function() {\r\n unbindExistingUserJoinedHandler();\r\n unbindReconnecting();\r\n unbindUserLeft();\r\n unbindEndpointsLoaded();\r\n unbindPresenceUpdated();\r\n unbindEndpointLogout();\r\n unbindCallConnected();\r\n });\r\n }\r\n getUsers() {\r\n return _users;\r\n }\r\n getUser(userName) {\r\n return _users[_users.findIndex((u) => u.userName === userName)];\r\n }\r\n get userCount() {\r\n return _users.length;\r\n }\r\n }\r\n\r\n angular\r\n .module('webcomm')\r\n .service('userService', [\r\n '$rootScope',\r\n '$log',\r\n 'wtcpjsClientProviderService',\r\n 'channelModel',\r\n 'endpointModel',\r\n 'dispositionService',\r\n UserService\r\n ]);\r\n})(angular)","angular\r\n .module('webcomm')\r\n .factory('wtcpjsClientProviderService', ['$log', '$timeout', '$rootScope', 'version', function ($log, $timeout, $rootScope, version) {\r\n let client;\r\n let webCommLicenseUUID = \"{576386DF-4D31-49B4-97F1-BAF8EECE19B5}\";\r\n\r\n function checkForMicrophone() {\r\n if (client.WTCPAudioStatus.status === 'inprogress') {\r\n $timeout(checkForMicrophone, 200);\r\n return;\r\n }\r\n\r\n if (client.WTCPAudioStatus.status !== 'ready') {\r\n $log.warn('Could not get microphone access');\r\n $rootScope.noMicrophone = true;\r\n $rootScope.$broadcast('client.noMicrophone');\r\n }\r\n }\r\n\r\n let service = {\r\n\r\n epFilterMaxNumEndpoints: 128,\r\n epFilterMaxNumChanEndpointsDisable: 256,\r\n createClient() {\r\n $log.warn(\"wtcpjsClientProviderService: creating a new client\");\r\n // 'webcomm_logging_level' is a global - it comes directly from index.html\r\n client = new WtcpJs.Client({\r\n audioPlayerActive: false,\r\n licenseUUID: webCommLicenseUUID,\r\n deviceId: this.getDeviceId(),\r\n applicationName: `MOT-WEBCOMM-${version}`,\r\n loggingLevel: webcomm_logging_level});\r\n checkForMicrophone(client);\r\n return client;\r\n },\r\n\r\n getClient() {\r\n return client;\r\n },\r\n\r\n filterTypes: {\r\n channelFilter: 1,\r\n privateCallChannelFilter: 2,\r\n privateCallChannelSelfFilter: 22, // This can go away now with latest trunk build proxy... it supports regex\r\n addressBookFilter: 7\r\n },\r\n\r\n getDeviceId() {\r\n return `webcomm-browser-${Math.random().toString(36).slice(2)}`;\r\n },\r\n\r\n setEndpointFilterThresholds(configInfo) {\r\n if(configInfo.endpoint_filter) {\r\n this.epFilterMaxNumEndpoints = configInfo.endpoint_filter.maxnumendpoints;\r\n this.epFilterMaxNumChanEndpointsDisable = configInfo.endpoint_filter.maxnumchanendpointsdisable;\r\n }\r\n }\r\n }\r\n\r\n return service;\r\n }]);","/* global angular */\r\nangular\r\n .module('webcomm')\r\n .factory('wtcpjsService', [\r\n '$rootScope', \r\n '$log', \r\n '$q', \r\n 'wtcpjsClientProviderService',\r\n 'muteService',\r\n 'locationService',\r\n 'channelModel', \r\n 'endpointModel',\r\n 'feedModel',\r\n 'profileModel',\r\n 'privateCallService',\r\n 'tupleDictionaryService',\r\n function($rootScope, $log, $q, wtcpjsClientProviderService, muteService, locationService, channelModel, endpointModel, feedModel, profileModel, privateCallService, tupleDictionaryService) {\r\n const INCOMING_AUDIO_SOUND_TIMEOUT_SECONDS = 5;\r\n const MAX_ACTIVE_CHANNELS = 16;\r\n var incomingAudioSoundPlayedAt;\r\n\r\n var channelsActivated = false;\r\n var deferredForChannelActivationFuncs = [];\r\n var service = {};\r\n var client = wtcpjsClientProviderService.getClient();\r\n \r\n var speakers = tupleDictionaryService;\r\n\r\n var myEndpointId; // isn't this always 1?\r\n var isSubscribed = false;\r\n var channelFilterId = wtcpjsClientProviderService.filterTypes.channelFilter;\r\n var privateTalkgroupSelfFilterId = wtcpjsClientProviderService.filterTypes.privateCallChannelSelfFilter;\r\n var privateTalkgroupFilterId = wtcpjsClientProviderService.filterTypes.privateCallChannelFilter;\r\n var addressBookFilterId = wtcpjsClientProviderService.filterTypes.addressBookFilter;\r\n var channelFilterActive = false;\r\n\r\n function activateChannels(channelIds) {\r\n channelsActivated = false;\r\n client.setEndpointPropertiesChannelActivityFilter(\"*\")\r\n .then(() => {\r\n $log.info(`activating channels: ${channelIds}`);\r\n\r\n //Need to add some code to test if any of the channelIds about to be activated are muted\r\n //and only disable the audio if there is\r\n client.AudioPlayerActive = false; // Disable all audio on client until we establish which channels (if any) are muted\r\n\r\n client.setActiveChannels(channelIds)\r\n .then(() => {\r\n $rootScope.$applyAsync(function($scope) {\r\n $log.info(`channels activated: ${channelIds}`);\r\n channelsActivated = true;\r\n\r\n while(deferredForChannelActivationFuncs.length > 0) {\r\n deferredForChannelActivationFuncs.shift()();\r\n }\r\n\r\n channelModel.resetReadyState(channelIds);\r\n $rootScope.$broadcast('wtcpjsService.activeChannelsChanged', channelIds);\r\n });\r\n })\r\n .catch((failedChannels) => {\r\n // Do something in UI to reflect the failure to activate one or more channels\r\n $log.error(\"One or more channels in your profile failed on activation\", failedChannels);\r\n });\r\n });\r\n }\r\n\r\n function playIncomingAudioSound() {\r\n // if incomingAudioSoundPlayedAt === undefined then secondsPassed = timeout + 1\r\n let secondsPassed = incomingAudioSoundPlayedAt ? (new Date().getTime() - incomingAudioSoundPlayedAt.getTime()) / 1000 : INCOMING_AUDIO_SOUND_TIMEOUT_SECONDS + 1;\r\n if (secondsPassed > INCOMING_AUDIO_SOUND_TIMEOUT_SECONDS) {\r\n new Audio('sounds/ptt_incoming_audio_received.mp3').play();\r\n }\r\n incomingAudioSoundPlayedAt = new Date();\r\n }\r\n\r\n function createEndpoint(channelId, endpointId, endpointName, endpointFlags) {\r\n let addSilently = channelId === 0 ? true : false;\r\n var newEndPoint = endpointModel.addEndpoint(\r\n channelId,\r\n endpointId,\r\n endpointName,\r\n endpointFlags,\r\n addSilently);\r\n\r\n // This means we are just now acquiring the endpoint that represents the current user in the Wave system\r\n if (!myEndpointId) {\r\n let shareLocationFunc = () => {\r\n if (locationService.isSharingEnabled) {\r\n locationService.shareLocation()\r\n .catch((err) => {\r\n $log.warn(err);\r\n });\r\n }\r\n }\r\n\r\n if(channelsActivated) {\r\n shareLocationFunc();\r\n } else {\r\n deferredForChannelActivationFuncs.push(shareLocationFunc);\r\n }\r\n myEndpointId = endpointModel.getMyEndpoint().id;\r\n }\r\n\r\n return newEndPoint;\r\n }\r\n\r\n function updateEndpointProperties(channelId, ep) {\r\n // Service endpoint, ex: media server recorder endpoint, file reader, etc...\r\n if (ep.properties.hasOwnProperty('state') && ep.properties.state === '0')\r\n return;\r\n\r\n if (ep.properties.disposition === 'Gone') {\r\n $rootScope.$broadcast(\"wtcpjsService.endpoint.gone\", ep.endpointId);\r\n return;\r\n }\r\n\r\n endpointModel.updateProperties(channelId, ep);\r\n }\r\n\r\n function clearChannelState(e, isReconnecting) {\r\n myEndpointId = void 0;\r\n speakers.init();\r\n if(!isReconnecting) {\r\n channelModel.clearPrivateCallChannels();\r\n channelModel.clearChannels();\r\n endpointModel.clearEndpoints();\r\n }\r\n }\r\n\r\n // SPEAKING\r\n var startSpeaking = function(channelId, endpoint) {\r\n // only play sound if the channel isn't muted\r\n if (!muteService.getMuteStatus(channelId)) {\r\n playIncomingAudioSound();\r\n }\r\n\r\n //console.log(`==> current speaker User Priority ${endpoint.UP} `);\r\n // pavel 5/20: the 'endpoint.name || endpoint.userName' is just so that the user sees _something_ until we get teh right\r\n // endpoint properties from the proxy\r\n speakers.put([channelId, endpoint.id], feedModel.addChannelFeedEvent(channelId, endpoint.name || endpoint.userName, \"speaking\", {\r\n endpointId: endpoint.id,\r\n UP: endpoint.UP,\r\n self: endpoint.flags.get(channelId).Self || endpoint.userName === endpointModel.getMyEndpoint().userName,\r\n startedSpeaking: new Date()\r\n }));\r\n };\r\n\r\n var stopSpeaking = function(channelId, endpoint) {\r\n feedModel.addChannelFeedEvent(channelId, endpoint.name, \"end-speaking\", { endpointId: endpoint.id, self: endpoint.flags.get(channelId).Self });\r\n if (typeof speakers.get([channelId,endpoint.id]) !== 'undefined') {\r\n speakers.get([channelId,endpoint.id]).data.finishedSpeaking = new Date();\r\n speakers.remove([channelId,endpoint.id]);\r\n }\r\n };\r\n\r\n var filterEndpoints = function(channelId) {\r\n\r\n if (channelId > 0) {\r\n $log.info(`wtcpjsService applying new endpoint filter for channel ${channelId}`);\r\n\r\n client\r\n .setEndpointChannelFilter(channelFilterId, channelId, { 'displayName': '*' }, \"*\", 0, new WtcpJs.AnchorInfo())\r\n .then((resp) => {\r\n\r\n if (resp.subErrorCode === 121) {\r\n endpointModel.setEndpointsDisabledOnChannel(channelId, wtcpjsClientProviderService.epFilterMaxNumChanEndpointsDisable);\r\n } else {\r\n if (resp.subErrorCode === 120) {\r\n endpointModel.setEndpointsTruncatedOnChannel(channelId);\r\n }\r\n endpointModel.clearEndpointsDisabledOnChannel(channelId);\r\n endpointModel.clearEndpointsTruncatedOnChannel(channelId);\r\n channelFilterActive = true;\r\n $rootScope.$applyAsync(function ($scope) {\r\n // We are reloading a fresh set of endpoints, so clear out the old ones\r\n endpointModel.clearChannelEndpoints(channelId);\r\n\r\n //Get endpoint info from response now\r\n endpointModel.initializeEndpoints(channelId, resp);\r\n });\r\n }\r\n })\r\n .catch((err) => {\r\n $log.error(\"TBD: REPLACE THIS ERROR: Failed to set Endpoint Channel Filter on Channel \" + channelId + \", \" + err.errorMessage, err);\r\n });\r\n } else if (channelId < 0) {\r\n $log.info('PrivateCall channel selected, wtcpjsService clearing channel filter');\r\n\r\n endpointModel.clearChannelEndpoints(channelId);\r\n\r\n if(channelFilterActive) {\r\n channelFilterActive = false;\r\n client.clearEndpointFilter(channelFilterId)\r\n .catch((err) => {\r\n $log.error(\"Unable to clear channel filter: \" + err.errorMessage);\r\n });\r\n }\r\n }\r\n };\r\n\r\n service.getMaxActiveChannelCount = () => MAX_ACTIVE_CHANNELS;\r\n \r\n // activate channels and broadcast the channel list\r\n service.updateChannels = (updatedChannels) => {\r\n channelModel.clearChannels();\r\n\r\n for (let channel of updatedChannels) {\r\n channelModel.addOrUpdateChannel(channel);\r\n\r\n feedModel.addChannelFeedEvent(channel.channelId, '', \"endpoint-joined\", '');\r\n }\r\n\r\n if (channelModel.getSelectedChannel() && !updatedChannels.includes(channelModel.getSelectedChannel().id)) {\r\n channelModel.clearSelectedChannel();\r\n }\r\n\r\n service.changeActiveChannels();\r\n };\r\n\r\n service.changeActiveChannels = () => {\r\n activateChannels(channelModel.getActiveChannelIds());\r\n };\r\n\r\n service.subscribeToEvents = () => {\r\n if (isSubscribed) {\r\n return;\r\n }\r\n else {\r\n isSubscribed = true;\r\n }\r\n \r\n client.onPTTOff.subscribe(function(x) {\r\n $rootScope.$applyAsync(function($scope) {\r\n $rootScope.$broadcast(\"wtcpjsService.pttOff\");\r\n });\r\n });\r\n\r\n client.onChannelActivity.subscribe(function(data) {\r\n $rootScope.$applyAsync(function($scope) {\r\n var channelId = data.channelId;\r\n var channel = channelModel.getChannel(channelId);\r\n channel.numEndpoints = data.numEndpoints;\r\n $log.debug(`onChannelActivity (${channelId}), data`, data);\r\n\r\n for (let proxyEP of data.endpoints) {\r\n\r\n let epId = proxyEP.endpointInfo.endpointId;\r\n let wcEndpoint = endpointModel.getChannelEndpoint(channelId, epId) ||\r\n createEndpoint(channelId, epId, proxyEP.endpointInfo.endpointName, proxyEP.endpointInfo.endpointFlags);\r\n\r\n // endpoint Gone\r\n if (proxyEP.endpointInfo.endpointFlags.Gone) {\r\n if(wcEndpoint.filterIds.includes(privateTalkgroupFilterId) ||\r\n wcEndpoint.filterIds.includes(privateTalkgroupSelfFilterId)) {\r\n let selectedChannelId = channelModel.getSelectedChannel().id;\r\n endpointModel.deleteEndpoint(selectedChannelId, epId);\r\n }\r\n endpointModel.deleteEndpoint(channelId, epId);\r\n\r\n } else {\r\n endpointModel.updateFlags(channelId, epId, proxyEP.endpointInfo.endpointFlags);\r\n }\r\n\r\n if (Object.getOwnPropertyNames(proxyEP.endpointProperties).length > 0) {\r\n // Massage the EndpointInfo into the same format as Unsolicited EP Prop Update\r\n proxyEP.properties = proxyEP.endpointProperties;\r\n proxyEP.endpointId = epId;\r\n updateEndpointProperties(channelId, proxyEP);\r\n }\r\n\r\n // the speaking is for [channelId, wcEndpoint.id] of tupleDictionary\r\n if (typeof speakers.get([channelId, wcEndpoint.id]) === 'undefined' && wcEndpoint.flags.get(channelId).Speaking) {\r\n startSpeaking(channelId, wcEndpoint);\r\n $rootScope.$broadcast(\"wtcpjsService.endpoint.speaking\", { endpointId: wcEndpoint.id, started: true });\r\n } else if (typeof speakers.get([channelId, wcEndpoint.id]) !== 'undefined' && !wcEndpoint.flags.get(channelId).Speaking) {\r\n stopSpeaking(channelId, wcEndpoint);\r\n $rootScope.$broadcast(\"wtcpjsService.endpoint.speaking\", { endpointId: proxyEP.endpointId, started: false });\r\n }\r\n }\r\n\r\n // select the the first channel if none are selected, ignoring the initial SPC related channel activity\r\n if (channelId > 0) {\r\n if (!channelModel.getSelectedChannel()) {\r\n channelModel.selectChannel(channelId);\r\n } else {\r\n if (!channel.ready && channelModel.getSelectedChannel().id === channel.id) {\r\n filterEndpoints(channel.id);\r\n }\r\n }\r\n channel.ready = true;\r\n }\r\n });\r\n });\r\n\r\n // TBD: Refactor this out of wtcpjsService. This really belongs in the endpointModel\r\n client.onEndpointPropertiesReceived.subscribe(function(ep) {\r\n $rootScope.$applyAsync(function($scope) {\r\n if (ep.filterIds.includes(channelFilterId) ||\r\n ep.filterIds.includes(privateTalkgroupFilterId) ||\r\n ep.filterIds.includes(privateTalkgroupSelfFilterId)) {\r\n let selectedChannelId = channelModel.getSelectedChannel().id;\r\n\r\n $log.debug(`onEndpointPropertiesReceived for channel ${selectedChannelId}`, ep);\r\n let endpoint = endpointModel.getEndpoint(ep.endpointId); // We have this because of SPC channel activity\r\n\r\n // Getting a bug here: TypeError: Cannot read property 'userName' of undefined\r\n // Seems to happen when endpoint signs out\r\n let wcEndpoint = endpointModel.getChannelEndpoint(selectedChannelId, ep.endpointId) ||\r\n createEndpoint(selectedChannelId, ep.endpointId, endpoint.userName, endpoint.flags.get(0));\r\n\r\n if(wcEndpoint) {\r\n updateEndpointProperties(selectedChannelId, ep);\r\n }\r\n\r\n }\r\n\r\n if (ep.filterIds.includes(addressBookFilterId)) {\r\n $log.debug('onEndpointPropertiesReceived for AddressBook', ep);\r\n updateEndpointProperties(0, ep);\r\n }\r\n });\r\n });\r\n\r\n client.onChannelPropertiesReceived.subscribe(function(event) {\r\n $rootScope.$applyAsync(function($scope) {\r\n var channel = channelModel.getChannel(event.channelId);\r\n $log.debug(`onChannelPropertiesReceived (${event.channelId})`, event, channel);\r\n\r\n let systemProps = event.properties.system;\r\n channel.update(\r\n systemProps.name,\r\n systemProps.transmitAudio === \"1\",\r\n systemProps.receiveAudio === \"1\",\r\n systemProps.simplex === \"1\"\r\n );\r\n\r\n $rootScope.$broadcast(\"wtcpjsService.channelPropertiesReceived\", channel);\r\n });\r\n });\r\n\r\n client.onProxyUpdated.subscribe(function(event) {\r\n $rootScope.$applyAsync(function($scope) {\r\n console.warn('onProxyUpdated', event);\r\n let channelId = event.channel;\r\n let changeType = event.changeType;\r\n\r\n switch (changeType) {\r\n case 1:\r\n channelModel.addEmptyChannel(channelId);\r\n profileModel.addChannelToCurrentProfile(channelId);\r\n service.changeActiveChannels();\r\n break; // add channel - the following onChannelPropertiesReceived will take care of the rest\r\n case 2:\r\n channelModel.removeChannel(channelId);\r\n profileModel.removeChannelFromCurrentProfile(channelId);\r\n service.changeActiveChannels();\r\n break;\r\n //$rootScope.$broadcast('channelRemoved', event.channel);\r\n case 3:\r\n break; // channel updated - leave and return\r\n case 4:\r\n break; // channel updated - channel props coming\r\n case 5:\r\n profileModel.updateProfileName(event.profileName);\r\n $rootScope.$broadcast('wtcpjsService.profileNameChanged', event.profileName); // profile name updated\r\n break;\r\n case 6:\r\n break; // phone lines updated\r\n default:\r\n }\r\n });\r\n });\r\n };\r\n\r\n $rootScope.$on('channelModel.channelSelected', (event, channel) => {\r\n filterEndpoints(channel.id);\r\n });\r\n\r\n $rootScope.$on('isReconnecting', (event, isReconnecting) => {\r\n if (isReconnecting) {\r\n channelFilterActive = false;\r\n myEndpointId = '';\r\n endpointModel.clearEndpoints();\r\n }\r\n });\r\n\r\n $rootScope.$on('ConnectionService.logout', clearChannelState);\r\n\r\n $rootScope.$on('ConnectionService.connectionClosed', clearChannelState);\r\n\r\n $rootScope.$on('ConnectionService.credentialsValidated', (event, data) => {\r\n if (!data.reconnect) {\r\n service.subscribeToEvents();\r\n }\r\n\r\n\r\n // Activate the first phone line. will need to add a phone line selection UI element to settings \r\n // To allow user to control which phone line they want to use for private calling\r\n if(data.phoneLines.length > 0) {\r\n privateCallService.activatePhoneLine(data.phoneLines[0]);\r\n }\r\n\r\n let channels = data.channels;\r\n\r\n if (channelModel.areChannelsNewOrChanged(channels)) {\r\n service.updateChannels(channels);\r\n }\r\n else { //No changes since reconnect, just reactivate the channels we already know about\r\n if (channelModel.reconnectedWithReducedActiveChannels(channels)) {\r\n activateChannels(channelModel.getActiveChannelIds());\r\n }\r\n else {\r\n activateChannels(channels.map(c => c.channelId));\r\n }\r\n }\r\n });\r\n\r\n $log.debug('wtcpjsService initialized');\r\n return service;\r\n }\r\n ]);\r\n","angular.module('webcomm').directive('clickOutside', ['$document', '$log', function ($document, $log) {\r\n return {\r\n link: function (scope, elem, attrs) {\r\n\r\n var onClick = function (event) {\r\n // ignore clicks on the the toggle link or children\r\n var ngclick = event.target.getAttribute('ng-click');\r\n var targetAttribute = '[ng-click=\"' + attrs.clickOutside + '\"]';\r\n var isToggle = $(event.target).closest(targetAttribute).length > 0;\r\n\r\n // ignore child links\r\n var isChild = $(elem).has(event.target).length > 0;\r\n var isSelf = elem[0] == event.target;\r\n\r\n // call toggle\r\n var isInside = isChild || isSelf || isToggle;\r\n if (!isInside) {\r\n scope.$apply(attrs.clickOutside);\r\n }\r\n\r\n }\r\n\r\n scope.$on('$destroy', function () {\r\n $document.unbind('click', onClick);\r\n });\r\n\r\n $document.bind('click', onClick);\r\n }\r\n };\r\n}]);","angular.module('webcomm')\r\n .directive('connectionHealth', ['$log', function($log) {\r\n function link(scope, element, attrs) {\r\n scope.status = 'gray';\r\n\r\n var unbindWatcher = scope.$watch('latency', function(value, oldvalue) {\r\n $log.info(\"connection health directive latency changed\", value, oldvalue);\r\n if(value) {\r\n if (value < 100) {\r\n scope.status = 'green';\r\n } else if (value < 200) {\r\n scope.status = 'yellow';\r\n } else {\r\n scope.status = 'red';\r\n }\r\n }\r\n });\r\n\r\n scope.$on('$destroy', function() {\r\n unbindWatcher();\r\n });\r\n }\r\n\r\n return {\r\n restrict: 'EA',\r\n link: link,\r\n scope: {\r\n latency: '='\r\n },\r\n template: '