mirror of
https://github.com/nasa/openmct.git
synced 2025-06-25 02:29:24 +00:00
Compare commits
3 Commits
dave/inspe
...
add-events
Author | SHA1 | Date | |
---|---|---|---|
e75cc35cb7 | |||
f216bd8769 | |||
79a430278e |
@ -38,7 +38,7 @@ define([
|
||||
};
|
||||
|
||||
IndicatorAPI.prototype.simpleIndicator = function () {
|
||||
return new SimpleIndicator(this.openmct);
|
||||
return new SimpleIndicator.default(this.openmct);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -20,82 +20,104 @@
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
define(['zepto', './res/indicator-template.html'],
|
||||
function ($, indicatorTemplate) {
|
||||
const DEFAULT_ICON_CLASS = 'icon-info';
|
||||
import EventEmitter from 'EventEmitter';
|
||||
import indicatorTemplate from './res/indicator-template.html';
|
||||
|
||||
function SimpleIndicator(openmct) {
|
||||
this.openmct = openmct;
|
||||
this.element = $(indicatorTemplate)[0];
|
||||
this.priority = openmct.priority.DEFAULT;
|
||||
const DEFAULT_ICON_CLASS = 'icon-info';
|
||||
|
||||
this.textElement = this.element.querySelector('.js-indicator-text');
|
||||
class SimpleIndicator extends EventEmitter{
|
||||
constructor(openmct) {
|
||||
super();
|
||||
|
||||
//Set defaults
|
||||
this.text('New Indicator');
|
||||
this.description('');
|
||||
this.iconClass(DEFAULT_ICON_CLASS);
|
||||
this.statusClass('');
|
||||
}
|
||||
this.openmct = openmct;
|
||||
this.element = compileTemplate(indicatorTemplate)[0];
|
||||
this.priority = openmct.priority.DEFAULT;
|
||||
|
||||
this.textElement = this.element.querySelector('.js-indicator-text');
|
||||
|
||||
//Set defaults
|
||||
this.text('New Indicator');
|
||||
this.description('');
|
||||
this.iconClass(DEFAULT_ICON_CLASS);
|
||||
this.statusClass('');
|
||||
|
||||
this.click = this.click.bind(this);
|
||||
|
||||
SimpleIndicator.prototype.text = function (text) {
|
||||
if (text !== undefined && text !== this.textValue) {
|
||||
this.textValue = text;
|
||||
this.textElement.innerText = text;
|
||||
|
||||
if (!text) {
|
||||
this.element.classList.add('hidden');
|
||||
} else {
|
||||
this.element.classList.remove('hidden');
|
||||
}
|
||||
}
|
||||
|
||||
return this.textValue;
|
||||
};
|
||||
|
||||
SimpleIndicator.prototype.description = function (description) {
|
||||
if (description !== undefined && description !== this.descriptionValue) {
|
||||
this.descriptionValue = description;
|
||||
this.element.title = description;
|
||||
}
|
||||
|
||||
return this.descriptionValue;
|
||||
};
|
||||
|
||||
SimpleIndicator.prototype.iconClass = function (iconClass) {
|
||||
if (iconClass !== undefined && iconClass !== this.iconClassValue) {
|
||||
// element.classList is precious and throws errors if you try and add
|
||||
// or remove empty strings
|
||||
if (this.iconClassValue) {
|
||||
this.element.classList.remove(this.iconClassValue);
|
||||
}
|
||||
|
||||
if (iconClass) {
|
||||
this.element.classList.add(iconClass);
|
||||
}
|
||||
|
||||
this.iconClassValue = iconClass;
|
||||
}
|
||||
|
||||
return this.iconClassValue;
|
||||
};
|
||||
|
||||
SimpleIndicator.prototype.statusClass = function (statusClass) {
|
||||
if (statusClass !== undefined && statusClass !== this.statusClassValue) {
|
||||
if (this.statusClassValue) {
|
||||
this.element.classList.remove(this.statusClassValue);
|
||||
}
|
||||
|
||||
if (statusClass) {
|
||||
this.element.classList.add(statusClass);
|
||||
}
|
||||
|
||||
this.statusClassValue = statusClass;
|
||||
}
|
||||
|
||||
return this.statusClassValue;
|
||||
};
|
||||
|
||||
return SimpleIndicator;
|
||||
this.element.addEventListener('click', this.click);
|
||||
openmct.once('destroy', () => {
|
||||
this.removeAllListeners();
|
||||
this.element.removeEventListener('click', this.click)
|
||||
})
|
||||
}
|
||||
);
|
||||
|
||||
text(text) {
|
||||
if (text !== undefined && text !== this.textValue) {
|
||||
this.textValue = text;
|
||||
this.textElement.innerText = text;
|
||||
|
||||
if (!text) {
|
||||
this.element.classList.add('hidden');
|
||||
} else {
|
||||
this.element.classList.remove('hidden');
|
||||
}
|
||||
}
|
||||
|
||||
return this.textValue;
|
||||
};
|
||||
|
||||
description(description) {
|
||||
if (description !== undefined && description !== this.descriptionValue) {
|
||||
this.descriptionValue = description;
|
||||
this.element.title = description;
|
||||
}
|
||||
|
||||
return this.descriptionValue;
|
||||
};
|
||||
|
||||
iconClass(iconClass) {
|
||||
if (iconClass !== undefined && iconClass !== this.iconClassValue) {
|
||||
// element.classList is precious and throws errors if you try and add
|
||||
// or remove empty strings
|
||||
if (this.iconClassValue) {
|
||||
this.element.classList.remove(this.iconClassValue);
|
||||
}
|
||||
|
||||
if (iconClass) {
|
||||
this.element.classList.add(iconClass);
|
||||
}
|
||||
|
||||
this.iconClassValue = iconClass;
|
||||
}
|
||||
|
||||
return this.iconClassValue;
|
||||
};
|
||||
|
||||
statusClass(statusClass) {
|
||||
if (statusClass !== undefined && statusClass !== this.statusClassValue) {
|
||||
if (this.statusClassValue) {
|
||||
this.element.classList.remove(this.statusClassValue);
|
||||
}
|
||||
|
||||
if (statusClass) {
|
||||
this.element.classList.add(statusClass);
|
||||
}
|
||||
|
||||
this.statusClassValue = statusClass;
|
||||
}
|
||||
|
||||
return this.statusClassValue;
|
||||
};
|
||||
|
||||
click(event) {
|
||||
this.emit('click', event);
|
||||
}
|
||||
}
|
||||
|
||||
function compileTemplate(htmlTemplate) {
|
||||
const templateNode = document.createElement('template');
|
||||
templateNode.innerHTML = htmlTemplate;
|
||||
|
||||
return templateNode.content.cloneNode(true).children;
|
||||
}
|
||||
|
||||
export default SimpleIndicator;
|
||||
|
207
src/plugins/operatorStatus/OperatorStatus.vue
Normal file
207
src/plugins/operatorStatus/OperatorStatus.vue
Normal file
@ -0,0 +1,207 @@
|
||||
<template>
|
||||
<div :style="position" class="c-menu" @click.stop="noop">
|
||||
<div>My Role: {{role}}</div>
|
||||
<div>Current Poll Question: {{currentPollQuestion}}</div>
|
||||
<div>Current Poll Date: {{pollQuestionUpdated}}</div>
|
||||
<div>My Status: {{roleStatus}}</div>
|
||||
<div>Set Status:
|
||||
<select v-model="selectedStatus" name="setStatus" @change="setStatus">
|
||||
<option v-for="status in allStatuses" :key="status.value" :value="status.value">{{status.label}}</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// TODO: Make this configuration
|
||||
const ROLES = ['Driver'];
|
||||
const POLL_TELEMETRY_POINT_ID = {
|
||||
namespace: 'taxonomy',
|
||||
key: '~ViperGround~OperatorStatus~PollQuestion'
|
||||
};
|
||||
const POLL_QUESTION_KEY = 'value';
|
||||
|
||||
const ROLE_STATUS_TELEMETRY_POINT_ID = {
|
||||
namespace: 'taxonomy',
|
||||
key: '~ViperGround~OperatorStatus~driverStatus'
|
||||
};
|
||||
const ROLE_STATUS_KEY = 'value';
|
||||
const SET_STATUS_URL = 'http://localhost:9000/viper-proxy/viper/yamcs/api/processors/viper/realtime/parameters/ViperGround/OperatorStatus/driverStatus';
|
||||
const STATUSES = [
|
||||
{
|
||||
value: 0,
|
||||
label: 'NO_STATUS'
|
||||
},{
|
||||
value: 1,
|
||||
label: 'NO_GO'
|
||||
},{
|
||||
value: 2,
|
||||
label: 'GO'
|
||||
},{
|
||||
value: 3,
|
||||
label: 'MAYBE'
|
||||
},
|
||||
]
|
||||
|
||||
export default {
|
||||
inject: ['openmct'],
|
||||
props: {
|
||||
positionX: {
|
||||
type: Number,
|
||||
required: true
|
||||
},
|
||||
positionY: {
|
||||
type: Number,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
role: '--',
|
||||
pollQuestionUpdated: '--',
|
||||
currentPollQuestion: '--',
|
||||
roleStatus: '--',
|
||||
selectedStatus: 'no-go',
|
||||
allStatuses: STATUSES
|
||||
};
|
||||
},
|
||||
async mounted() {
|
||||
this.unsubscribe = [];
|
||||
this.fetchAllStatuses();
|
||||
|
||||
await this.fetchTelemetryObjects();
|
||||
this.setMetadata();
|
||||
this.fetchCurrentPoll();
|
||||
this.fetchMyStatus();
|
||||
this.subscribeToMyStatus();
|
||||
this.subscribeToPollQuestion();
|
||||
|
||||
this.findFirstApplicableRole();
|
||||
},
|
||||
methods: {
|
||||
fetchAllStatuses() {
|
||||
//this.allStatuses = openmct.user.getAllStatuses();
|
||||
},
|
||||
async fetchTelemetryObjects() {
|
||||
const telemetryObjects = await Promise.all([
|
||||
this.openmct.objects.get(ROLE_STATUS_TELEMETRY_POINT_ID),
|
||||
this.openmct.objects.get(POLL_TELEMETRY_POINT_ID)
|
||||
]);
|
||||
|
||||
this.roleStatusTelemetryObject = telemetryObjects[0];
|
||||
this.pollQuestionTelemetryObject = telemetryObjects[1];
|
||||
},
|
||||
setMetadata() {
|
||||
const roleStatusMetadata = openmct.telemetry.getMetadata(this.roleStatusTelemetryObject);
|
||||
const roleStatusMetadataValue = roleStatusMetadata.value(ROLE_STATUS_KEY);
|
||||
|
||||
const pollQuestionMetadata = openmct.telemetry.getMetadata(this.pollQuestionTelemetryObject);
|
||||
const pollQuestionMetadataValue = pollQuestionMetadata.value(POLL_QUESTION_KEY);
|
||||
|
||||
const timestampMetadataValue = pollQuestionMetadata.value(this.openmct.time.timeSystem().key);
|
||||
|
||||
this.timestampFormatter = openmct.telemetry.getValueFormatter(timestampMetadataValue);
|
||||
this.statusFormatter = openmct.telemetry.getValueFormatter(roleStatusMetadataValue);
|
||||
this.pollQuestionFormatter = openmct.telemetry.getValueFormatter(pollQuestionMetadataValue);
|
||||
},
|
||||
async findFirstApplicableRole() {
|
||||
const userRolesMap = await Promise.all(ROLES.map((role) => this.openmct.user.hasRole(role)));
|
||||
const index = userRolesMap.findIndex((hasRole) => hasRole);
|
||||
|
||||
this.role = ROLES[index];
|
||||
},
|
||||
async fetchCurrentPoll() {
|
||||
//const pollMessage = await openmct.user.getCurrentPollQuestion();
|
||||
|
||||
const pollMessages = await this.openmct.telemetry.request(this.pollQuestionTelemetryObject, {
|
||||
strategy: 'latest',
|
||||
// TODO: THIS IS A HACK, NEED A WAY TO ALWAYS GET THE LAST VALUE FROM ANY TIME WINDOW (maybe getParameterValue()? What happens if there is nothing in the cache though (eg after a restart))
|
||||
start: 0,
|
||||
end: Date.now()
|
||||
});
|
||||
|
||||
if (pollMessages.length > 0) {
|
||||
const datum = pollMessages[pollMessages.length - 1];
|
||||
|
||||
this.setPollQuestionFromDatum(datum);
|
||||
}
|
||||
|
||||
},
|
||||
setPollQuestionFromDatum(datum) {
|
||||
this.currentPollQuestion = this.pollQuestionFormatter.format(datum);
|
||||
this.pollQuestionUpdated = this.timestampFormatter.format(datum);
|
||||
},
|
||||
async fetchMyStatus() {
|
||||
// const currentUser = this.openmct.user.getCurrentUser();
|
||||
// const status = await this.openmct.user.getStatus(currentUser);
|
||||
|
||||
// TODO: Make role-specific
|
||||
const roleStatuses = await this.openmct.telemetry.request(this.roleStatusTelemetryObject, {
|
||||
strategy: 'latest',
|
||||
start: 0,
|
||||
end: Date.now()
|
||||
});
|
||||
|
||||
if (roleStatuses.length > 0) {
|
||||
const datum = roleStatuses[roleStatuses.length - 1];
|
||||
|
||||
this.setRoleStatusFromDatum(datum);
|
||||
}
|
||||
},
|
||||
subscribeToMyStatus() {
|
||||
// const currentUser = this.openmct.user.getCurrentUser();
|
||||
// this.openmct.user.onUserStatusChange(currentUser, this.setRoleStatus);
|
||||
|
||||
this.unsubscribe.push(this.openmct.telemetry.subscribe(this.roleStatusTelemetryObject, (datum) => {
|
||||
this.setRoleStatusFromDatum(datum);
|
||||
}));
|
||||
},
|
||||
subscribeToPollQuestion() {
|
||||
this.unsubscribe.push(this.openmct.telemetry.subscribe(this.roleStatusTelemetryObject, (datum) => {
|
||||
this.setRoleStatusFromDatum(datum);
|
||||
}));
|
||||
},
|
||||
setRoleStatusFromDatum(datum) {
|
||||
this.roleStatus = this.statusFormatter.format(datum);
|
||||
this.selectedStatus = this.findStatus(this.roleStatus);
|
||||
},
|
||||
findStatus(status) {
|
||||
return (STATUSES.find(s => s.label === status) || STATUSES[0]).value;
|
||||
},
|
||||
async setStatus(status) {
|
||||
// Where does 'status' come from. What does it look like?
|
||||
// Could be provided as an enum from the user API.
|
||||
|
||||
//const result = await openmct.user.setStatus(user, status);
|
||||
|
||||
// const newDatum = openmct.telemetry.newDatumFromValues(this.statusDomainObject)
|
||||
// const result = await openmct.telemetry.setValue(this.statusDomainObject, newDatum);
|
||||
|
||||
const fetchResult = await fetch(SET_STATUS_URL, {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
type: 'UINT32',
|
||||
uint32Value: `${this.selectedStatus}`
|
||||
})
|
||||
});
|
||||
},
|
||||
noop() {}
|
||||
},
|
||||
computed: {
|
||||
position() {
|
||||
return {
|
||||
position: 'absolute',
|
||||
left: `${this.positionX}px`,
|
||||
top: `${this.positionY}px`
|
||||
}
|
||||
}
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.unsubscribe.forEach(unsubscribe => unsubscribe);
|
||||
}
|
||||
|
||||
};
|
||||
</script>
|
135
src/plugins/operatorStatus/PollQuestion.vue
Normal file
135
src/plugins/operatorStatus/PollQuestion.vue
Normal file
@ -0,0 +1,135 @@
|
||||
<template>
|
||||
<div :style="position" class="c-menu" @click.stop="noop">
|
||||
<div>Current Poll Question: {{currentPollQuestion}}</div>
|
||||
<div>Current Poll Date: {{pollQuestionUpdated}}</div>
|
||||
<div>Set Poll Question:
|
||||
<input type="text" v-model="newPollQuestion" name="newPollQuestion" @change="setPollQuestion">
|
||||
</div>
|
||||
<div><button class="c-button" @click="clearAllResponses"> Clear All Responses</button></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const POLL_TELEMETRY_POINT_ID = {
|
||||
namespace: 'taxonomy',
|
||||
key: '~ViperGround~OperatorStatus~PollQuestion'
|
||||
};
|
||||
const POLL_QUESTION_KEY = 'value';
|
||||
|
||||
const SET_POLL_QUESTION_URL = 'http://localhost:9000/viper-proxy/viper/yamcs/api/processors/viper/realtime/parameters/ViperGround/OperatorStatus/PollQuestion';
|
||||
const CLEAR_RESPONSES_URL = 'http://localhost:9000/viper-proxy/viper/yamcs/api/processors/viper/realtime/parameters:batchSet';
|
||||
|
||||
export default {
|
||||
inject: ['openmct'],
|
||||
props: {
|
||||
positionX: {
|
||||
type: Number,
|
||||
required: true
|
||||
},
|
||||
positionY: {
|
||||
type: Number,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
pollQuestionUpdated: '--',
|
||||
currentPollQuestion: '--',
|
||||
newPollQuestion: undefined
|
||||
};
|
||||
},
|
||||
async mounted() {
|
||||
this.unsubscribe = [];
|
||||
this.pollQuestionTelemetryObject = await this.openmct.objects.get(POLL_TELEMETRY_POINT_ID);
|
||||
|
||||
this.setMetadata();
|
||||
this.fetchCurrentPoll();
|
||||
this.subscribeToPollQuestion();
|
||||
},
|
||||
methods: {
|
||||
setMetadata() {
|
||||
const pollQuestionMetadata = openmct.telemetry.getMetadata(this.pollQuestionTelemetryObject);
|
||||
const pollQuestionMetadataValue = pollQuestionMetadata.value(POLL_QUESTION_KEY);
|
||||
const timestampMetadataValue = pollQuestionMetadata.value(this.openmct.time.timeSystem().key);
|
||||
|
||||
this.timestampFormatter = openmct.telemetry.getValueFormatter(timestampMetadataValue);
|
||||
this.pollQuestionFormatter = openmct.telemetry.getValueFormatter(pollQuestionMetadataValue);
|
||||
},
|
||||
async fetchCurrentPoll() {
|
||||
const pollMessages = await this.openmct.telemetry.request(this.pollQuestionTelemetryObject, {
|
||||
strategy: 'latest',
|
||||
// TODO: THIS IS A HACK, NEED A WAY TO ALWAYS GET THE LAST VALUE FROM ANY TIME WINDOW (maybe getParameterValue()? What happens if there is nothing in the cache though (eg after a restart))
|
||||
start: 0,
|
||||
end: Date.now()
|
||||
});
|
||||
|
||||
if (pollMessages.length > 0) {
|
||||
const datum = pollMessages[pollMessages.length - 1];
|
||||
|
||||
this.setPollQuestionFromDatum(datum);
|
||||
}
|
||||
|
||||
},
|
||||
subscribeToPollQuestion() {
|
||||
this.unsubscribe.push(this.openmct.telemetry.subscribe(this.pollQuestionTelemetryObject, (datum) => {
|
||||
this.setPollQuestionFromDatum(datum);
|
||||
}));
|
||||
},
|
||||
setPollQuestionFromDatum(datum) {
|
||||
this.currentPollQuestion = this.pollQuestionFormatter.format(datum);
|
||||
this.pollQuestionUpdated = this.timestampFormatter.format(datum);
|
||||
},
|
||||
async setPollQuestion() {
|
||||
//const response = await this.openmct.user.setPollQuestion(this.newPollQuestion);
|
||||
|
||||
await fetch(SET_POLL_QUESTION_URL, {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
type: 'STRING',
|
||||
stringValue: `${this.newPollQuestion}`
|
||||
})
|
||||
});
|
||||
this.newPollQuestion = undefined;
|
||||
},
|
||||
clearAllResponses() {
|
||||
//this.openmct.user.clearAllStatuses();
|
||||
|
||||
fetch(CLEAR_RESPONSES_URL, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
request: [{
|
||||
id: {
|
||||
name: "/ViperGround/OperatorStatus/driverStatus",
|
||||
},
|
||||
value: {
|
||||
type: 'UINT32',
|
||||
uint32Value: '0'
|
||||
}
|
||||
//TODO: Also set all the other operator status parameters
|
||||
}]
|
||||
})
|
||||
});
|
||||
},
|
||||
noop() {}
|
||||
},
|
||||
computed: {
|
||||
position() {
|
||||
return {
|
||||
position: 'absolute',
|
||||
left: `${this.positionX}px`,
|
||||
top: `${this.positionY}px`
|
||||
}
|
||||
}
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.unsubscribe.forEach(unsubscribe => unsubscribe);
|
||||
}
|
||||
|
||||
};
|
||||
</script>
|
89
src/plugins/operatorStatus/plugin.js
Normal file
89
src/plugins/operatorStatus/plugin.js
Normal file
@ -0,0 +1,89 @@
|
||||
/**
|
||||
* Could potentially be implemented using the User API to make this "generic" (although only supported from Yamcs initially)
|
||||
*/
|
||||
|
||||
import OperatorStatusComponent from './OperatorStatus.vue';
|
||||
import PollQuestionComponent from './PollQuestion.vue';
|
||||
|
||||
import Vue from 'vue';
|
||||
|
||||
export default function operatorStatusPlugin(config) {
|
||||
return function install(openmct) {
|
||||
|
||||
/**
|
||||
Operator Status
|
||||
*/
|
||||
const operatorStatusElement = new Vue({
|
||||
components: {
|
||||
OperatorStatus: OperatorStatusComponent
|
||||
},
|
||||
provide: {
|
||||
openmct
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
positionX: 0,
|
||||
positionY: 0
|
||||
}
|
||||
},
|
||||
template: '<operator-status :positionX="positionX" :positionY="positionY" />'
|
||||
}).$mount();
|
||||
|
||||
const operatorIndicator = openmct.indicators.simpleIndicator();
|
||||
|
||||
operatorIndicator.text("My Operator Status");
|
||||
operatorIndicator.description("Set my operator status");
|
||||
operatorIndicator.iconClass('icon-check');
|
||||
operatorIndicator.on('click', (event) => {
|
||||
//Don't propagate, otherwise this event will trigger the listener below and remove itself.
|
||||
event.stopPropagation();
|
||||
document.body.appendChild(operatorStatusElement.$el);
|
||||
operatorStatusElement.positionX = event.clientX;
|
||||
operatorStatusElement.positionY = event.clientY;
|
||||
|
||||
document.addEventListener('click', event => {
|
||||
operatorStatusElement.$el.remove();
|
||||
}, {once: true});
|
||||
});
|
||||
|
||||
openmct.indicators.add(operatorIndicator);
|
||||
|
||||
/**
|
||||
Poll Question
|
||||
*/
|
||||
const pollQuestionElement = new Vue({
|
||||
components: {
|
||||
PollQuestion: PollQuestionComponent
|
||||
},
|
||||
provide: {
|
||||
openmct
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
positionX: 0,
|
||||
positionY: 0
|
||||
}
|
||||
},
|
||||
template: '<poll-question :positionX="positionX" :positionY="positionY" />'
|
||||
}).$mount();
|
||||
|
||||
const pollQuestionIndicator = openmct.indicators.simpleIndicator();
|
||||
|
||||
pollQuestionIndicator.text("Poll Question");
|
||||
pollQuestionIndicator.description("Set the current poll question");
|
||||
pollQuestionIndicator.iconClass('icon-draft');
|
||||
pollQuestionIndicator.on('click', (event) => {
|
||||
//Don't propagate, otherwise this event will trigger the listener below and remove itself.
|
||||
event.stopPropagation();
|
||||
document.body.appendChild(pollQuestionElement.$el);
|
||||
pollQuestionElement.positionX = event.clientX;
|
||||
pollQuestionElement.positionY = event.clientY;
|
||||
|
||||
document.addEventListener('click', event => {
|
||||
pollQuestionElement.$el.remove();
|
||||
}, {once: true});
|
||||
});
|
||||
|
||||
openmct.indicators.add(pollQuestionIndicator);
|
||||
};
|
||||
};
|
@ -76,7 +76,8 @@ define([
|
||||
'./timer/plugin',
|
||||
'./userIndicator/plugin',
|
||||
'../../example/exampleUser/plugin',
|
||||
'./localStorage/plugin'
|
||||
'./localStorage/plugin',
|
||||
'./operatorStatus/plugin'
|
||||
], function (
|
||||
_,
|
||||
UTCTimeSystem,
|
||||
@ -133,7 +134,8 @@ define([
|
||||
Timer,
|
||||
UserIndicator,
|
||||
ExampleUser,
|
||||
LocalStorage
|
||||
LocalStorage,
|
||||
OperatorStatus
|
||||
) {
|
||||
const plugins = {};
|
||||
|
||||
@ -210,6 +212,7 @@ define([
|
||||
plugins.DeviceClassifier = DeviceClassifier.default;
|
||||
plugins.UserIndicator = UserIndicator.default;
|
||||
plugins.LocalStorage = LocalStorage.default;
|
||||
plugins.OperatorStatus = OperatorStatus.default;
|
||||
|
||||
return plugins;
|
||||
});
|
||||
|
Reference in New Issue
Block a user