I want my chrome extension to take a notification.id, and:
Update an existing notification if it does exist.
OR
Create a new notification if it doesn't exist.
Calling clear() then create() is not ideal, since the animation is visually jarring for both remove() and create() methods, where I want to update without animations. Plus, obviously, calling update() on a disappeared notification doesn't do anything.
Is there an easy way to implement this?
Edit: This approach no longer works on any platform except ChromeOS due to the removal of Chrome's Notification Center.
Possible ideas to work around it include using requireInteraction: true flag on notifications to fully control notification lifetime.
There is a dirty trick for re-showing a notification. If you change a notification's priority to a higher value, it will be re-shown if it exists.
function createOrUpdate(id, options, callback) {
// Try to lower priority to minimal "shown" priority
chrome.notifications.update(id, {priority: 0}, function(existed) {
if(existed) {
var targetPriority = options.priority || 0;
options.priority = 1;
// Update with higher priority
chrome.notifications.update(id, options, function() {
chrome.notifications.update(id, {priority: targetPriority}, function() {
callback(true); // Updated
});
});
} else {
chrome.notifications.create(id, options, function() {
callback(false); // Created
});
}
});
}
Xan's answer no longer works on Windows, MacOS, or Linux. At this point the only way to make sure your notification displays, no matter what, is to create a new notification.
If you want to prevent multiple notifications from being on screen, you'll have to clear the old notification and replace it with a new one. This is demonstrated below.
NOTIFICATION_ID = "some_random_string";
function showNotification ( ... , callback) {
chrome.notifications.clear(NOTIFICATION_ID, function(cleared) {
var options = {
// whatever
};
chrome.notifications.create(NOTIFICATION_ID, options, callback);
});
}
Of course, this results in an animation of existing notification getting dismissed and a new notification immediately taking its place, but unfortunately this is unavoidable.
Related
I have an object wich caches windows with all their internal structure (form, other ui elements). So when a user opens a window which has already been cached, it does create it from scratch, but takes if from cache and just show it like this:
winCache[id_group].show();
So, for each id_group, there is a window which may be cached in winCache. The problem is that I want to reset a form, which is inside the window, and populate it with new data from database. I try to do it like this:
if(winCache[id_group]){
winCache[id_group].removeListener('show');
winCache[id_group].addListener('show', function () {
populate_form(this, id_field); // <-- this method retreives data from database
// and sets the form
});
winCache[id_group].show();
}
else { // window was not cached and has to be created from scratch
var win = ...
win.show();
// ... some BIG procedure
winCache[id_group] = win; // next time it will be taken from cache
}
But the problem is, for some insane reason, ExtJS duplicates show listeners infinitely. So, for example, if I open winCache[10] seven times for the same id_group = 10, but for different id_fields (id_field = 1, id_field = 2, ..., id_field = 7), then show listener will be triggered seven times - for each id_field. And that is incredible stupidity. So, my question is why ExtJS duplicates listeners? And why doesn't removeListener work???
The removeListener expects a function reference as the second argument.
If this code you've added is executed each time the window should be displayed may be using single: true on the addListener will solve your issue (so you don't need to removeListener), try:
winCache[id_group].addListener('show', function () {
}, null, { single: true });
If that's not the case, you'll need to save a reference to the show function you'r passing to addListener so you'll be able to pass it to removeListener, or may be use destroyable, like:
winCache[id_group].destroyShowEvent && winCache[id_group].destroyShowEvent.destry();
winCache[id_group].destroyShowEvent = winCache[id_group].addListener('show', function () {
}, null, { destroyable: true });
References: https://developer.chrome.com/apps/notifications
I am using the chrome.notifications.create(string id, object options, function callback); to create a chrome notification.
var id = 'list';
var options = {};
options.title = 'test';
options.iconUrl = 'notification_icon.png';
options.type = 'list';
options.message = "test";
options.buttons = [{title: 'test'}];
options.items = [{title: 'test', message:'test'}];
var createCallback = function(notificationId) { console.log(notificationId); };
chrome.notifications.create(id, options, createCallback); // returns 'list';
This creates a notification as expected. All working correctly.
I then call chrome.notification.clear(string id, function callback);
var id = 'list';
var clearCallback= function(wasCleared) { console.log(wasCleared); };
chrome.notification.clear(id, clearCallback); // returns true;
This does clear the notification. All working correctly.
EXCEPT it does not clear the notification out if the notification panel is open. This is not a major problem 99% of the time. Until I implemented the button code within the notification.
Using chrome.notifications.onButtonClicked.addListener(function callback); On click I am calling the clear notification panel code, and it reports back as it has been cleared.
var onButtonClickedCallback = function (notificationId, buttonIndex) {
console.log(notificationId, buttonIndex);
if ( notificationId == 'list' ) {
chrome.notification.clear(id, clearCallback); // returns true;
}
}
chrome.notifications.onButtonClicked.addListener(onButtonClickedCallback); // onClick it returns 'list', 0
But I am looking right at it.. Once the notification panel closes and opens again, I can confirm it has actually gone. But obviously since I am clicking a button on the notification, the panel is open, but it does not clear away as I would have liked.
All this is running in an extension background without the persistence: false property (so the script is always loaded, and since I can see the output, I know the functions are being called).
Have I overlooked something? I do not see any functions that deal with closing the notification panel. So as far as I can tell, I am clearing the notification but the panel is not updating it's display.
I am using Chrome 37.0.2019.0 canary on Win8
If anyone can suggest something I may have missed, I would be greatful. My google searches reveal people having problems with the HTML notification.
This is a known bug, or rather an old design decision, with little progress.
Star the issue to raise its priority. I also suffer from the same.
Here's the workaround solution I've been using for several months now:
// open a window to take focus away from notification and there it will close automatically
function openTemporaryWindowToRemoveFocus() {
var win = window.open("about:blank", "emptyWindow", "width=1, height=1, top=-500, left=-500");
win.close();
}
chrome.notifications.clear("", function(wasCleared) {
openTemporaryWindowToRemoveFocus()
});
I’ve made a one page site. When user clicks on the menu buttons, content is loaded with ajax.
It works fine.
In order to improve SEO and to allow user to copy / past URL of different content, i use
function show_content() {
// change URL in browser bar)
window.history.pushState("", "Content", "/content.php");
// ajax
$content.load("ajax/content.php?id="+id);
}
It works fine. URL changes and the browser doesn’t reload the page
However, when user clicks on back button in browser, the url changes and the content have to be loaded.
I've done this and it works :
window.onpopstate = function(event) {
if (document.location.pathname == '/4-content.php') {
show_content_1();
}
else if (document.location.pathname == '/1-content.php') {
show_content_2();
}
else if (document.location.pathname == '/6-content.php') {
show_content_();
}
};
Do you know if there is a way to improve this code ?
What I did was passing an object literal to pushState() on page load. This way you can always go back to your first created pushState. In my case I had to push twice before I could go back. Pushing a state on page load helped me out.
HTML5 allows you to use data-attributes so for your triggers you can use those to bind HTML data.
I use a try catch because I didn't had time to find a polyfill for older browsers. You might want to check Modernizr if this is needed in your case.
PAGELOAD
try {
window.history.pushState({
url: '',
id: this.content.data("id"), // html data-id
label: this.content.data("label") // html data-label
}, "just content or your label variable", window.location.href);
} catch (e) {
console.log(e);
}
EVENT HANDLERS
An object filled with default information
var obj = {
url: settings.assetsPath, // this came from php
lang: settings.language, // this came from php
historyData: {}
};
Bind the history.pushState() trigger. In my case a delegate since I have dynamic elements on the page.
// click a trigger -> push state
this.root.on("click", ".cssSelector", function (ev) {
var path = [],
urlChunk = document.location.pathname; // to follow your example
// some data-attributes you need? like id or label
// override obj.historyData
obj.historyData.id = $(ev.currentTarget).data("id");
// create a relative path for security reasons
path.push("..", obj.lang, label, urlChunk);
path = path.join("/");
// attempt to push a state
try {
window.history.pushState(obj.historyData, label, path);
this.back.fadeIn();
this.showContent(obj.historyData.id);
} catch (e) {
console.log(e);
}
});
Bind the history.back() event to a custom button, link or something.
I used .preventDefault() since my button is a link.
// click back arrow -> history
this.back.on("click", function (ev) {
ev.preventDefault();
window.history.back();
});
When history pops back -> check for a pushed state unless it was the first attempt
$(window).on("popstate", function (ev) {
var originalState = ev.originalEvent.state || obj.historyData;
if (!originalState) {
// no history, hide the back button or something
this.back.fadeOut();
return;
} else {
// do something
this.showContent(obj.historyData.id);
}
});
Using object literals as a parameter is handy to pass your id's. Then you can use one function showContent(id).
Wherever I've used this it's nothing more than a jQuery object/function, stored inside an IIFE.
Please note I put these scripts together from my implementation combined with some ideas from your initial request. So hopefully this gives you some new ideas ;)
I need to set up a custom script for tracking a users click through on a form submission field. This is what I've got so far. As the user navigates down through the form fields the counter variable (base) totals up how far along the path the user has reached. I want to send the results off when the user leaves the page by sending out the base variable. I'm thinking of using the .unload function in jQuery. However for some reason unload isn't responding the way I think it should. Any ideas?
var base = 0; //declares a variable of 0. This should refresh when a new user lands on the form page.
function checkPath(fieldNo, path) { //this function should check the current base value of the base variable vs the current fieldNo
if (fieldNo >= path) { //checks to see if base if lower than fieldNo
base = fieldNo; //if true, base is set to current fieldNo
return base;
} else {
return base; //if false, simply returns base.
}
};
$('#order_customer_fields_forename').focus(function () { //when the form box is selected should run checkPath then alert result.
checkPath(1, base);
});
$('#order_customer_fields_surname').focus(function () {
checkPath(2, base);
});
$('#order_customer_fields_postcode').focus(function () {
checkPath(3, base);
});
$('#order_customer_fields_address1').focus(function () {
checkPath(4, base);
});
$('#order_customer_fields_address2').focus(function () {
checkPath(5, base);
});
$(window).unload(function () {
alert(base);
});
The unload event fires too late for the effect you need. You should try using the onbeforeunload event using either vanilla Javascript:
window.onbeforeunload = function (e) {
// Your code here
};
Or jQuery:
$(window).bind('beforeunload', function (e) {
// Your code here
});
Either way, you should be aware that this is not an ideal solution for what you are trying to achieve. This event is implemented unevenly across browsers. Chrome seems to be the most restrictive, and IE the most permissive, in its implementation.
A different direction you may want to take is sending the data to the server by XHR whenever the user completes a field.
There is a way to detect from javascript if the google earth plugin is crashed, so I can reload automatically the page without user action?
Thanks
I don't think you can directly assess whether the plug-in has crashed. However, you could set up an endless timer that is constantly checking something like getView()
function hasCrashed() {
try {
var view = ge.getView();
if (view) {
// plugin good
} else {
// plugin not good
}
} catch (e) {
// plugin not good
}
// a timer that checks every second
setTimeout('hasCrashed()', 1000);
}
I haven't tested that, but it should work. If not, try other options besides from getView() - perhaps getWindow() or getGlobe() options