Presently I have set time interval in such a way that every 1 seconds,a function is executed.The problem is that,i am displaying notification through this function.There are notification buttons in notification.When I click on the notification action button,mulitple windows are being open.I found out that it is because I have set Timer.But in my extension , timer is necessary in order to check the output of a server file everytime.Anyone please help me.Is there any other way to deal this problem
Here is my background.js
var myNotificationID = null;
var oldChromeVersion = !chrome.runtime;
setInterval(function() {
updateIcon();
}, 1000);
function onInit() {
updateIcon();
if (!oldChromeVersion) {
chrome.alarms.create('watchdog',{periodInMinutes:5,delayInMinutes: 0});
}
}
function onAlarm(alarm) {
if (alarm && alarm.name == 'watchdog') {
onWatchdog();
}
else {
updateIcon();
}
}
function onWatchdog() {
chrome.alarms.get('refresh', function(alarm) {
if (alarm) {
console.log('Refresh alarm exists. Yay.');
}
else {
updateIcon();
}
});
}
if (oldChromeVersion) {
updateIcon();
onInit();
}
else {
chrome.runtime.onInstalled.addListener(onInit);
chrome.alarms.onAlarm.addListener(onAlarm);
}
function updateIcon(){
if(//something)
//something
else{
chrome.notifications.create(
'id1',{
type: 'basic',
iconUrl: '/calpine_not_logged_in.png',
title: 'Warning : Attendance',
message: 'Please mark your Attendance !',
buttons: [{ title: 'Mark',
iconUrl: '/tick.jpg'
},{ title: 'Ignore',
iconUrl: '/cross.jpg'}],
priority: 0},
function(id) { myNotificationID = id;}
);
chrome.notifications.onButtonClicked.addListener(function(notifId, btnIdx) {
if (notifId === myNotificationID) {
if (btnIdx === 0) {
window.open("http://www.calpinemate.com/");
} else if (btnIdx === 1) {
notification.close();
}
}
});
chrome.notifications.onClosed.addListener(function() {
notification.close();
});
}
} }
});
}
}
onInit();
Here i found out that,when i remove the delayInminutes and laso the set timeineterval it opens only one tab,as i want.But both of them are necessary to do continuous checking of a server file.because whole my operation is based on the server file output.Is there any way to cope with this problem.Is there any way to set time interval for only that function?
The problem has nothing to do with what you "suspect". The problem is that you add a listener for chrome.notifications.onButtonClicked events inside the updateIcon() function. So this is what happens:
Every second you execute updateIcon().
Inside updateIcon() you set a new listener that listens for notification-buttons being clicked.
So, after 1 second there will be 1 listener, after 2 seconds there will be 2 listeners, after n seconds there will be n listeners.
When you click the button, each listener will catch the onButtonClicked event and open a new window. (So there will be so many windows as many seconds have elapsed since you loaded your extension.
How to fix this:
You need to create the listener only once (and not every second). To remove the following piece of code from inside the updateIcon() function:
chrome.notifications.onButtonClicked.addListener(function(notifId, btnIdx) {
if (notifId === myNotificationID) {
if (btnIdx === 0) {
window.open("http://www.calpinemate.com/");
} else if (btnIdx === 1) {
notification.close();
}
}
});
And place it at the end of your background-page (just before onInit();). Make sure you don't place it inside any function.
Related
I'm using the VM2 package to run user code. I'm trying to intercept console output and have set the NodeVM object's console property to 'redirect':
// Create a new sandbox VM for this request
const vm = new NodeVM( {
console: 'redirect',
timeout: 30000,
sandbox: { request, state, response },
require: {
external: true
}
});
According to the documentation that redirects console output to 'events'. I'm new to NodeJS, how do I hook into those events to capture the console.log messages executed inside the Sandbox?
After digging through the source code, I found this file where the event emit is occuring:
sandbox.js
if (vm.options.console === 'inherit') {
global.console = Contextify.readonly(host.console);
} else if (vm.options.console === 'redirect') {
global.console = {
log(...args) {
vm.emit('console.log', ...Decontextify.arguments(args));
return null;
},
info(...args) {
vm.emit('console.info', ...Decontextify.arguments(args));
return null;
},
warn(...args) {
vm.emit('console.warn', ...Decontextify.arguments(args));
return null;
},
error(...args) {
vm.emit('console.error', ...Decontextify.arguments(args));
return null;
},
dir(...args) {
vm.emit('console.dir', ...Decontextify.arguments(args));
return null;
},
time: () => {},
timeEnd: () => {},
trace(...args) {
vm.emit('console.trace', ...Decontextify.arguments(args));
return null;
}
};
}
All you need to do to listen to these events is to bind an event listener on the vm you've created:
// Create a new sandbox VM for this request
const vm = new NodeVM( {
console: 'redirect',
require: {
external: ['request']
}
});
vm.on('console.log', (data) => {
console.log(`VM stdout: ${data}`);
});
Likewise, you can bind to console.log, console.info, console.warn, console.error, console.dir, and console.trace. Hopefully this will save someone else some time.
I am following the azure device twin tutorial https://learn.microsoft.com/en-us/azure/iot-hub/iot-hub-csharp-node-twin-how-to-configure
I can make this work to update an existing reported property. What I am not sure about is how can I add a new reported property.
Specifically the code looks snippet looks like:
var currentTelemetryConfig = twin.properties.reported.telemetryConfig;
currentTelemetryConfig.pendingConfig =
twin.properties.desired.telemetryConfig;
currentTelemetryConfig.status = "Pending";
telemetryConfig: currentTelemetryConfig
var patch = {
telemetryConfig: currentTelemetryConfig
};
twin.properties.reported.update(patch, function(err) {
if (err) {
console.log(err);
} else {
console.log('success');
}
}
I can easily understand how this works for the existing property update (in this case the telemetryConfig) but what would it look like if the change I was trying to make was to a entirely new property?
How would it work if I decide at some point the I want a a new desired property called "favourite_colour" : "blue"?
In the azure backend I can add this but how do I dynamically build the var patch variable?
I tried this but it returned an error:
twin.properties.reported.update(twin.properties.desired, function(err) {
if (err) {
console.log('Could not report properties');
} else {
console.log('Success');
}
});
This is what my twin looks like:
"properties": {
"desired": {
"active": true,
"pws": "xyz",
"$metadata": {
"$lastUpdated": "2018-03-27T18:21:57.010036Z",
"$lastUpdatedVersion": 5,
"active": {
"$lastUpdated": "2018-03-27T18:21:57.010036Z",
"$lastUpdatedVersion": 5
},
"pws": {
"$lastUpdated": "2018-03-27T18:21:57.010036Z",
"$lastUpdatedVersion": 5
}
},
"$version": 5
},
"reported": {
"telemetryConfig": 6,
"$metadata": {
"$lastUpdated": "2018-03-27T18:56:05.2445399Z",
"telemetryConfig": {
"$lastUpdated": "2018-03-27T18:56:05.2445399Z"
}
},
"$version": 5
}
}
}
I'm guessing you want to:
Add new reported property on device side (favourite_colour)
I first recommend you to read this sample in GitHub.
Main this sample shows different way to listen for updates in twin on different level. The top most, where any update in device twin will trigger an event; or specific property (favourite_color).
I've edited the sample from the Microsoft document you provided to work with favorite_color.
'use strict';
var Client = require('azure-iot-device').Client;
var Protocol = require('azure-iot-device-mqtt').Mqtt;
var connectionString = '{iot hub connection string}';
var client = Client.fromConnectionString(connectionString, Protocol);
var initConfigChange = function(twin, patch) {
twin.properties.reported.update(patch, function(err) {
if (err) {
console.log('Could not report properties');
} else {
console.log('Reported pending config change: ' + JSON.stringify(patch));
setTimeout(function() {completeConfigChange(twin, patch);}, 30000);
}
});
}
var completeConfigChange = function(twin, patch) {
if (patch.telemetryConfig) {
// Same as Sample
} else if (patch.favourite_colour) {
var currentfavourite_colour = twin.properties.reported.favourite_colour;
currentfavourite_colour.color = currentfavourite_colour.pendingConfig.color;
currentfavourite_colour.status = "Success";
delete currentfavourite_colour.pendingConfig;
var patch = {
favourite_colour: currentfavourite_colour
};
patch.favourite_colour.pendingConfig = null;
}
twin.properties.reported.update(patch, function(err) {
if (err) {
console.error('Error reporting properties: ' + err);
} else {
console.log('Reported completed config change: ' + JSON.stringify(patch));
}
});
};
client.open(function(err) {
if (err) {
console.error('could not open IotHub client');
} else {
client.getTwin(function(err, twin) {
if (err) {
console.error('could not get twin');
} else {
console.log('retrieved device twin');
twin.properties.reported.favourite_colour = {
color: "green"
}
twin.on('properties.desired', function(desiredChange) {
console.log("received change: "+JSON.stringify(desiredChange));
if (desiredChange.telemetryConfig) {
// Same as sample
} else if (desiredChange.favourite_colour) {
var currentfavourite_colour = twin.properties.reported.favourite_colour;
currentfavourite_colour.pendingConfig = twin.properties.desired.favourite_colour;
currentfavourite_colour.status = "Pending Color";
var patch = {
favourite_colour: currentfavourite_colour
};
initConfigChange(twin, patch);
}
});
}
});
}
});
What I did was use a if else statement to check the reported property; as I mentioned there are other ways to do this, check the GitHub code I provided earlier. Once I have the matched reported property I can update the in the same way as the existing sample.
I'm using the 1.3 requirement set for setting/getting the body value of an appointment/meeting: Office.context.mailbox.item.body.getAsync(...) and Office.context.mailbox.item.body.setAsync(...)
This works just fine literally everywhere and for all account types(Exchange on-premise and Outlook/Office365 accounts) except Outlook 2016 for MAC, where it fails to apply the html/text value of the body.
Checking the requirement sets (https://dev.office.com/reference/add-ins/outlook/tutorial-api-requirement-sets) MAC Outlook is listed as supporting all the requirement set versions(1.1 to 1.5) so it should support also the getAsync and setAsync methods for body property.
Any idea why it does not work?
UPDATE:
For setting value:
function applyBody() {
const $dBod = $.Deferred();
try {
Office.context.mailbox.item.body.setAsync(_appointmentInfo.body.value, { coercionType: _appointmentInfo.body.type }, function (asyncResult) {
if (asyncResult.status === Office.AsyncResultStatus.Succeeded) {
$dBod.resolve();
}
else {
$dBod.reject(translate.getTranslation('ERROR_SETTING_BODY'));
}
});
}
catch (e) {
$dBod.reject(e);
}
return $dBod.promise();
}
For getting value:
function getBody() {
const $dBod = $.Deferred();
getBodyType()
.done(function (bodyType) {
try {
Office.context.mailbox.item.body.getAsync(bodyType, function (asyncResult) {
if (asyncResult.status === Office.AsyncResultStatus.Succeeded) {
$dBod.resolve({ value: asyncResult.value, type: bodyType });
}
else {
$dBod.reject(translate.getTranslation('ERROR_GETTING_BODY_VALUE'));
}
});
}
catch (e) {
$dBod.reject(e);
}
})
.fail($dBod.reject);
return $dBod.promise();
}
For getting body type:
function getBodyType() {
const $dBod = $.Deferred();
try {
Office.context.mailbox.item.body.getTypeAsync(function (asyncResult) {
if (asyncResult.status === Office.AsyncResultStatus.Succeeded) {
$dBod.resolve(asyncResult.value);
}
else {
$dBod.reject(translate.getTranslation('ERROR_GETTING_BODY_TYPE'));
}
});
}
catch (e) {
$dBod.reject(e);
}
return $dBod.promise();
}
UPDATE2:
Method I use for concatenating initial body value with my html:
const filterNullsAndUndefined = function (array, char) {
return array.filter(function (val) { return val; }).join(char);
};
I call it like this filterNullsAndUndefined([intialBodyValue, myHtml],'');
Where in my case the initialBodyValue is the value I get using body.getAsync(...) before appending myHtml to it( in order to preserve any text the user inserted before myHtml template gets appended).
If I set myHtml directly on the body (overwrite) it works.
UPDATE 3:
Below the result we got when we appended the word 'Christmass':
appointment body as text
We are able to reproduce the issue. Adding a <b>Text</b> after the </html> works on Outlook 2016 desktop, but not on the Mac. We will be fixing this soon.
I added the IceCandidate after completing the offer and answer, but it still calls errors: 'RTCPeerConnection': the icecandidate cannot be added. This is part of my code:
else if (data.user_type == 'signaling') {
if (!rtcPeerConn)
startSignaling();
var message = JSON.parse(data.user_data);
if (message.sdp) {
rtcPeerConn.setRemoteDescription(new RTCSessionDescription(message.sdp),
function () { // if we received an offer, we need to answer
if (rtcPeerConn.remoteDescription.type == 'offer' && myUserType=="doctor") {
rtcPeerConn.createAnswer(sendLocalDesc, logError);
}
}, logError);
} else {
rtcPeerConn.addIceCandidate(new RTCIceCandidate(message.candidate));
}
}
I've read about onMessage.addListener method in Chrome to pass some data from extensions to script. What I have now:
popup.js
window.onload = function(){
document.getElementById('searchButton').onclick = searchText;
};
function searchText(){
var search = document.getElementById('searchText').value; // f.ex "123"
if(search){
chrome.tabs.query({active:true,currentWindow:true},function(tabs){
chrome.tabs.executeScript(tabs[0].id,{file:search.js});
chrome.tabs.sendMessage(tabs[0].id,{method:'search',searchText:search});
});
}
}
search.js
chrome.runtime.onMessage.addListener(function(message,sender,sendResponse){
alert('text');
});
However, alert ('text') is never fired. What's the problem?
You should quote "search.js" and put the chrome.tabs.sendMessage call in the callback of chrome.tabs.executeScript:
function searchText(){
var search = document.getElementById('searchText').value; // f.ex "123"
if (search) {
chrome.tabs.query({active:true,currentWindow:true}, function(tabs) {
chrome.tabs.executeScript(tabs[0].id, {
file: 'search.js'
}, function() {
chrome.tabs.sendMessage(tabs[0].id, {
method: 'search',
searchText: search
});
});
});
}
}
If this suggestion does not help, inspect the popup and look for error messages.