Are you able to update a webkitNotifications? - javascript

Had a look around an can only really find resources on creating notifications, and not updating them. Heard it might be possible if I used chrome.notifications instead but again can't find anyway to do it.
This currently is my code, and it ends up just closing any previous notification then reissuing it.
if (window.webkitNotifications){
if(window.webkitNotifications.checkPermission() > 0){
}
else if (seconds == 0)
{
var thumb = 'images/icon.png';
var title = 'Current Task';
var body = "Active " + hours + " hours and " + minutes + " minutes";
if (popup != "") {
popup.cancel();
}
popup = window.webkitNotifications.createNotification(thumb, title, body);
popup.show();
}
}
Anyone know if it's possible to update a notification instead of just recreate it? Would make it much more user friendly, and for a live feed of information more of a float over any other job they might be doing?

Once the notification has been created, the way to communicate with it is through message passing. Read up on it here: http://developer.chrome.com/extensions/messaging.html
Timeline:
Background process creates notification with content. Notifiation is created and starts listening for messages, all well and good.
Background process finds new information and checks whether the notification is still alive (via a variable in localStorage or usage of the Tabs API, or however you want to do this).
If notification was found to be alive, background process passes a message about new information, which the notification picks up and displays.

Related

Click counter without javascript

I'm using this javascript for a click counter in my blogger blog:
function clickCounter() {
if(typeof(Storage) !== "undefined") {
if (sessionStorage.clickcount) {
sessionStorage.clickcount = Number(sessionStorage.clickcount)+1;
} else {
sessionStorage.clickcount = 1;
}
document.getElementById("result").innerHTML = "Correct! " + sessionStorage.clickcount + " Smart answers 'til now.";
} else {
document.getElementById("result").innerHTML = "Sorry, your browser does not support this quiz...";
}
}
<button onclick="clickCounter()" type="button">Suspension</button>
Is there any way to create something similar through a non javascript method?
Can you help me triger an event (extra text message through popup or within the page) every 5, 10, 20, 100 clicks?
Thank you very much
HTML, and the Web in general, was designed to be stateless.
When you pull up a page, it should be like the first time -- and every time -- you pull up the page.
Since then, people have come up with a number of techniques to add state -- to save data, but they all involved one of two methods -- or sometimes both.
Method 1: Store state on the server.
This method uses HTML forms or cookies to slip information to the server when you load and reload a page.
Method 2: Store state in the client
While there are some older versions of Internet Explorer that can be coded in VBA, we are going to ignore that. The only "real" way to run any kind of code on the client, to store any data, is to use JavaScript.
Method 3: Use the client to talk to the server
Using Ajax, you can let your client talk to the server, but without doing a page reload. This still uses JavaScript.
So, to answer your question:
Without a server
Without JavaScript
No, you cannot save or store anything.
I have not tried this but...
What if you put multiple buttons positioned on top of each other. As each one is clicked, it can be made to vanish with something like
a:visited { display: none; }
The ones that need to display a message (5th, 10th, etc.) have different behavior attached.
See on click hide this (button link) pure css

Weird (caching) issue with Express/Node

I've built an angular/express/node app that runs in google cloud which currently uses a JSON file that serves as a data source for my application. For some reason, (and this only happens in the cloud) when saving data through an ajax call and writing it to the json file, everything seems to work fine. However, when refreshing the page, the server (sometimes!) sends me the version before the edit. I can't tell whether this is an Express-related, Node-related or even Angular-related problem, but what I know for sure is that I'm checking the JSON that comes in the response from the server, and it really is sometimes the modified version, sometimes not, so it most probably isn't angular cache-related.
The GET:
router.get('/concerts', function (request, response) {
delete require.cache[require.resolve('../database/data.json')];
var db = require('../database/data.json');
response.send(db.concerts);
});
The POST:
router.post('/concerts/save', function (request, response) {
delete require.cache[require.resolve('../database/data.json')];
var db = require('../database/data.json');
var concert = request.body;
console.log('Received concert id ' + concert.id + ' for saving.');
if (concert.id != 0) {
var indexOfItemToSave = db.concerts.map(function (e) {
return e.id;
}).indexOf(concert.id);
if (indexOfItemToSave == -1) {
console.log('Couldn\'t find concert with id ' + concert.id + 'in database!');
response.sendStatus(404);
return;
}
db.concerts[indexOfItemToSave] = concert;
}
else if (concert.id == 0) {
concert.id = db.concerts[db.concerts.length - 1].id + 1;
console.log('Concert id was 0, adding it with id ' + concert.id + '.');
db.concerts.push(concert);
}
console.log("Added stuff to temporary db");
var error = commit(db);
if (error)
response.send(error);
else
response.status(200).send(concert.id + '');
});
This probably doesn't say much, so if someone is interested in helping, you can see the issue live here. If you click on modify for the first concert and change the programme to something like asd and then save, everything looks fine. But if you try to refresh the page a few times (usually even up to 6-7 tries are needed) the old, unchanged programme is shown. Any clue or advice greatly appreciated, thanks.
To solve: Do not use local files to store data in cloud! This is what databases are for!
What was actually the problem?
The problem was caused by the fact that the App Engine had 2 VM instances running for my application. This caused the POST request to be sent to one instance, it did its job, saved the data by modifying its local JSON file, and returned a 200. However, after a few refreshes, the load balancing causes the GET to arrive at the other machine, which has its individual source code, including the initial, unmodified JSON. I am now using a MongoDB instance, and everything seems to be solved. Hopefully this discourages people who attempt to do the same thing I did.

Javascript -- any way to force a draw of new elements before processing?

I have a javascript function or two that takes a few seconds to process. I want to show an activity indicator so users don't think it's hung. I tried bootstrap animated progress bars and spin.js -- the problem is, I put the code for them before the processing, but the browser doesn't seem to update to show the new elements until after the function has finished. Obviously, an activity indicator that shows up after processing isn't incredibly useful. Is there a way to force the redraw before the processing occurs?
EDIT: here's an example code. This is from an HTA application, hence the pulling of files and such. I know the forced "wait" portion is a bad idea, usually, but in this program, files are opened and closed immediately, this is to prevent a race conflict and I just want to give it a quick 10 retry timeout before it tells them something is wrong. So, the problem is that this.spin() doesn't display its good until after the alert pops up.
Database.prototype.tryDatabase = function(fileName, toEdit, table, keepAlive) {
if (typeof keepAlive === 'undefined') keepAlive = false;
for (timeInd=0; timeInd < 5; timeInd++) {
var complete = this._addToFile(fileName, toEdit, table, keepAlive);
if (complete === false) {
var until = moment().valueOf() + 2000;
this.spin();
while (moment().valueOf() <= until) {;}
}
else break;
}
if (complete === false) window.alert("Database was locked for an extended period, please try again");
else if (!keepAlive) $('#added_to_db_modal').modal('show');
return complete;
}

simpleWebRTC with php backend

I am using simpleWebRTC with xhr to implement peculiar multi-users video chat (no audio)
my main issue in short: i was unable to attach the username from php to the correct video in JS
in my quetion i will
1. explain what i have done - and what are my current issues
2. if my current route is impossible - then i ask for suggestions for a different course of action on my part :-) - my knowledge is in JS and PHP|
the multi-users video allows to chose a few users and see them in a one way connection.
lets say we have users A, B, C, D
user A chooses to see users B, C, D while user B for example only chooses to see users C and D .... and so on
in simpleWebRTC i thought of two courses of action
a. one room for all of the participants and then to filter them down (was unsuccessful as i was unable to attach the correct username to each video - to filter them out)
2. instead i created a room (with username - email, as id) and let each user connect to the appropriate room.
in the first part of the code i have an XHR that pulls a list of the people the user wishes to subscribe to there videos (i.e: chooses to see)
var remoteRoom = [];
$.get('scripts/video/ours/musesSimpleList.php', function(msg){
myRoom = msg.username;
var remoteRoomArray = $.each( msg.museUsername, function(key, value){
remoteRoom.push = value;
return remoteRoom;
});
afterRoomDefined(myRoom, remoteRoomArray);
}, 'json');
function afterRoomDefined(myRoom, remoteRoomArray) is called after the list of people this specific user chose to register to was retrieved from MySQl
in this function, i now try to implement the WebRTC:
function afterRoomDefined(myRoom, remoteRoom){
console.log('remote room name: '+ remoteRoom + ' type: '+ $.type(remoteRoom));
remoteRoom = JSON.stringify(remoteRoom);
console.log('isArray '+$.isArray(remoteRoom));
//Create our WebRTC connection
var webrtc = new SimpleWebRTC({
url:'https://signaling.simplewebrtc.com:443',
//the element that will hold the local video
localVideoEl: 'localVideo',
//the element that will hold remote videos
//remoteVideosEl: 'remotes',
remoteVideosEl: '',
autoRequestMedia: true,
media: {
video: true,
audio: false
},
});
webrtc.mute();
// a peer video has been added
var i = 0;
//When it's ready and we have a room from the URL, join the call
webrtc.on('readyToCall', function(peer){
//each user first creates a room for himself - so other users could connect to
if(myRoom) webrtc.joinRoom(myRoom);
//here a room is created for every person the user subscribed to. each person created a room with his own username (when he opened this page in his browser) - in the line above. so now i open rooms with the same names - so the users will see each other (two ways now)
for(var b=0; b<remoteRoom.museUsername.length; b++){
console.log('remoteRoom loop - separate values: '+ remoteRoom.museUsername[b]);
if(remoteRoom.museUsername[b]) webrtc.joinRoom(remoteRoom.museUsername[b]);
}
});
// a peer video has been added
webrtc.on('videoAdded', function (video, peer) {
var remotes = document.getElementById('remotes');
if (remotes) {
var container = document.createElement('div');
container.className = 'videoContainer'+i;
$(container).attr('data-username', remoteRoom.museUsername[i]);
i++;
container.id = 'container_' + webrtc.getDomId(peer);
container.appendChild(video);
// suppress contextmenu
video.oncontextmenu = function () { return false; };
remotes.appendChild(container);
//this is to remove the other party video - if a user only subscribed to another user - the other user is not
//$('#remotes div:not[data-username]').css('border', 'red 5px solid');
$('#remotes div:not[data-username]').remove();
}
i=i+1;
});
webrtc.on('videoRemoved', function (video, peer) {
var remotes = document.getElementById('remotes');
var el = document.getElementById(peer ? 'container_' + webrtc.getDomId(peer) : 'localScreenContainer');
$('#remotes div').css('border', '#F4171A 2px solid');
if (remotes && el) {
remotes.removeChild(el);
}
});
That's it. and that basically works.
There are three issues though:
a. when one of the users refreshes his page (usually navigate back an forth) his own video is added again (two videos of the same user now - one of them is frozen) to all the other users who watches him. perhaps its an issue with
webrtc.on('videoRemoved'...
b. when user A for example registers to user B... - if user C than subscribes to user A - he will see also user B
the main issue perhaps is:
c. i was never really able to attach the username to the right video under:
webrtc.on('videoAdded',....
$(container).attr('data-username', remoteRoom.museUsername[i]);...
in the main block code.
I used
$('#remotes div:not[data-username]').remove();
to find all videos without username and kick (videos who were duplicated and froze+the other side of the video if user A subscribed to user B and not vice versa so user B will not see user A and so that C will not see in the above explanation) them out - but the username it self is not attached to the correct child in the right order (the moment someone refreshes the page the order scrambles....
am i going the right direction?
i had a look at pubNub, xirsys, firebase and some other solutions
(google appengine - java knowledge required, html5Rocks, easyRTC, signalMaster (no proper explanation on how to use)- but it seems that they all require node.js )
is my current mode of action (php and XHR) is a valid one?
if not - will one of the other solution will be relatively simple and plausible.
I started looking through too many api's and am confused by now
thank you :-)
It's hard to see exactly what goes wrong, because you seems to face multiple issue here, including webRTC in general and DOM insertion/removal problems.
If you are seeking for webRTC solution using PubNub, you should take a look at:
https://github.com/stephenlb/webrtc-sdk
and the demo that you can try:
http://stephenlb.github.io/webrtc-sdk/
also, check out
http://www.pubnub.com/blog/building-a-webrtc-video-and-voice-chat-application/

Stop people having my website loaded on multiple tabs

I want users to browse my site from only one tab in their browser. How can this be done? Would I use javascript and cookies?
For example, I have a website: www.example.com - and I want my clients to only be able to visit the site from one single tab in one browser. If they open another tab and load the site (or a subpage of the site) - I want an alert "Can't open multiple instances", and then redirect them to an error page.
Once thing to note - if the user changes the address from www.example.com/action/door/mine.aspx to www.example.com - that should work fine, because the user is in the same (original) tab.
Any help will be appreciated. Thanks in advance.
I've created a simple solution for this. The master page layout creates a tab GUID and stores it in sessionStorage area of the tab. The using an event listener on the storage area I write the tab GUID to the sites localStorage area. The listener then compares the tabs GUID to the one written to site storage and if they differ then it knows more than one tab is open.
So if I have three tabs A,B,C then click something in tab C, tab A and B detect another tab is open and warn user of this. I haven't yet got to fixing it so the last tab used get's notification, work in progress.
Here's the JS I have in master page, plus in the login page I have a localStorage.Clear to clear last tab from previous session.
// multi tab detection
function register_tab_GUID() {
// detect local storage available
if (typeof (Storage) !== "undefined") {
// get (set if not) tab GUID and store in tab session
if (sessionStorage["tabGUID"] == null) sessionStorage["tabGUID"] = tab_GUID();
var guid = sessionStorage["tabGUID"];
// add eventlistener to local storage
window.addEventListener("storage", storage_Handler, false);
// set tab GUID in local storage
localStorage["tabGUID"] = guid;
}
}
function storage_Handler(e) {
// if tabGUID does not match then more than one tab and GUID
if (e.key == 'tabGUID') {
if (e.oldValue != e.newValue) tab_Warning();
}
}
function tab_GUID() {
function s4() {
return Math.floor((1 + Math.random()) * 0x10000)
.toString(16)
.substring(1);
}
return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
s4() + '-' + s4() + s4() + s4();
}
function tab_Warning() {
alert("Another tab is open!");
}
Note: It's IE9+
Hope this helps.
UPDATE - 2020
Client side implementation:
We can make use of Broadcast Channel API which allows communication across browsing contexts (windows, tabs, frames or iframes) provided both contexts are from same origin.
A simple implementation to detect 2nd tab loading the website from the 1st tab:
//in entry point of your app (index.js)
const channel = new BroadcastChannel('tab');
channel.postMessage('another-tab');
// note that listener is added after posting the message
channel.addEventListener('message', (msg) => {
if (msg.data === 'another-tab') {
// message received from 2nd tab
alert('Cannot open multiple instances');
}
});
This doesn't use localStorage or cookies and it even works if 1st tab is offline and 2nd tab is being loaded.
Note: This is not supported in Safari & IE11 yet :(
UPDATE - 2022
From March 2022, it is now officially supported on Safari 🥳
Take a note on its browser compatibility.
However, there's a polyfill available that does the job.
EDIT2:
It's the exact thing which is mentioned at this answer, You need 2 IDs:
One random one
One consistent one (this will be our SSID actually, since you limit tabs of a single browser, it's better to get generated form browser's unique parameters)
You can generate consistent one from browser's user-agent or get it from server-side. store both of them server-side.
Store the random one in window.name property which is tab-specific.
Send a heartbeat every 1~2 seconds to your server containing both consistent ID and random one. if server fails to receive the heartbeat, it cleans up database and de-register dead clients.
on every browser's request, check window.name for the value. if it were missing, check with the server-side whether if the previous tab is closed or not (cleaned from database).
If yes, generate a new pair for client if no, reject them.
Two suggestions on top of my mind:
Server-side (better): provide all your clients, a user name and password. request them on their first visit of your site to enter with their credentials. then on every other request, check for whether user with said credentials is already logged in or not.
Client *
|
|
Server ---> Check whether
Already logged
or not?
______________
| |
yes no
| |
permit reject
them them
Client-side: If you really need a strong check of this, use evercookie to store an already-logged-in cookie on client's machine.
Side-note: Do know that every attempt in client side is not secure at all! client-side should help server-side, it shouldn't be used as the one and only source of security. even evercookies can be deleted so, give my first suggestion a go.
**EDIT:**
Evercookie is really doing a good job at storing most secure zombie cookies ever but since the library itself is a little bit heavy for browsers (storing a cookie takes more than 100ms each time) it's not really recommended for using in real-world web app.
use these instead if you went with server-side solution:
Way around ASP.NET session being shared across multiple tab windows
Kiranvj's answer
Extending rehman_00001's answer to handle the case where you want the alert on the new tabs instead.
const channel = new BroadcastChannel('tab');
let isOriginal = true;
channel.postMessage('another-tab');
// note that listener is added after posting the message
channel.addEventListener('message', (msg) => {
if (msg.data === 'another-tab' && isOriginal) {
// message received from 2nd tab
// reply to all new tabs that the website is already open
channel.postMessage('already-open');
}
if (msg.data === 'already-open') {
isOriginal = false;
// message received from original tab
// replace this with whatever logic you need
alert('Cannot open multiple instances');
}
});
I know this post is pretty old, but in case it helps anybody, I recently looked into basically doing the same thing using localStorage and sessionStorage.
Similar Anthony's answer, it sets an interval to make sure the originating tab keeps the entry fresh, so that if the browser crashes or somehow closes without calling the unload event (included in the comments but not part of the code for testing purposes), then there would just be a short delay before the application would run properly in a new browser window.
Obviously, you would change the "tab is good", "tab is bad" conditions to do whatever logic you want.
Oh, and also, the createGUID method is just a utility to make the session identifier unique... it is from this answer to a previous question (wanted to make sure I wasn't taking credit for that).
https://jsfiddle.net/yex8k2ts/30/
let localStorageTimeout = 15 * 1000; // 15,000 milliseconds = 15 seconds.
let localStorageResetInterval = 10 * 1000; // 10,000 milliseconds = 10 seconds.
let localStorageTabKey = 'test-application-browser-tab';
let sessionStorageGuidKey = 'browser-tab-guid';
function createGUID() {
let guid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
/*eslint-disable*/
let r = Math.random() * 16 | 0,
v = c == 'x' ? r : (r & 0x3 | 0x8);
/*eslint-enable*/
return v.toString(16);
});
return guid;
}
/**
* Compare our tab identifier associated with this session (particular tab)
* with that of one that is in localStorage (the active one for this browser).
* This browser tab is good if any of the following are true:
* 1. There is no localStorage Guid yet (first browser tab).
* 2. The localStorage Guid matches the session Guid. Same tab, refreshed.
* 3. The localStorage timeout period has ended.
*
* If our current session is the correct active one, an interval will continue
* to re-insert the localStorage value with an updated timestamp.
*
* Another thing, that should be done (so you can open a tab within 15 seconds of closing it) would be to do the following (or hook onto an existing onunload method):
* window.onunload = () => {
localStorage.removeItem(localStorageTabKey);
};
*/
function testTab() {
let sessionGuid = sessionStorage.getItem(sessionStorageGuidKey) || createGUID();
let tabObj = JSON.parse(localStorage.getItem(localStorageTabKey)) || null;
sessionStorage.setItem(sessionStorageGuidKey, sessionGuid);
// If no or stale tab object, our session is the winner. If the guid matches, ours is still the winner
if (tabObj === null || (tabObj.timestamp < new Date().getTime() - localStorageTimeout) || tabObj.guid === sessionGuid) {
function setTabObj() {
let newTabObj = {
guid: sessionGuid,
timestamp: new Date().getTime()
};
localStorage.setItem(localStorageTabKey, JSON.stringify(newTabObj));
}
setTabObj();
setInterval(setTabObj, localStorageResetInterval);
return true;
} else {
// An active tab is already open that does not match our session guid.
return false;
}
}
if (testTab()) {
document.getElementById('result').innerHTML = 'tab is good';
} else {
document.getElementById('result').innerHTML = 'tab is bad';
}
window.addEventListener('load', function () {
if (localStorage.getItem('web_browser') == null) {
// new tab
localStorage.setItem('web_browser', 'true');
window.addEventListener('unload', function() {
localStorage.removeItem('web_browser');
})
} else {
// duplicate tab
return;
}
})
Put this script at the beginning of html pages, where you don't want users to duplicate current page or tab.
The same problem (and solution) : https://sites.google.com/site/sarittechworld/track-client-windows
Similar :
http://www.codeproject.com/Articles/35859/Detect-and-prevent-multiple-windows-or-tab-usage-i
The best way to solve this is to have one-time session IDs.
Eg, each page contain a session ID, that is valid for one visit, is unique, and random.
When clicking any one link, it will use & invalidate the session ID, and the new page will have a new session ID.
This will force the user to always browse in the newest window or tab, and also prevents session stealing over the wire.
Any attempt to reuse a old session ID should immediately kill also the active session IDs for that user.
Its also important to store, in the session management system, which pages is accessible from page X. So if page X (with session ID abc) contains links to page 1, 2 and 3, any attempt to visit page 4 with session ID abc, will fail and also kill the session.
This will force the user to always have one single session track, and always follow the logic on the site. Any attempt to go forward, back, using history or log entires, or opening multiple windows or tabs, will fail and logout the user in all windows, tabs and devices.
All this can be completely implemented on server-side, without any client-side logic.
Why do you want to do this?
Could try to do some ugly hacking, but the result would be: There is no way you could completely suppress this behaviour.
This could not be solved by JavaScript, because there is always the possibility that the user has disabled JavaScript in his browser, or allows only a certain subset.
The user could open a new browser, use a different computer, etc. to visit multiple pages at once.
But more important:
Also, your site would be the only site that has this behaviour and for this reason this will confuse everybody which uses your site, because it doesn't work like a web site should work. Everybody who tries to open a second tab will think: "This is odd. This website sucks because it different then websites should be. I will not come again!" ;-)
I wrote this to stop a call center page from being accessed in multiple tabs. It works well and is purely client-side. Just update the else if part to do what you want if it detects a new tab.
// helper function to set cookies
function setCookie(cname, cvalue, seconds) {
var d = new Date();
d.setTime(d.getTime() + (seconds * 1000));
var expires = "expires="+ d.toUTCString();
document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/";
}
// helper function to get a cookie
function getCookie(cname) {
var name = cname + "=";
var decodedCookie = decodeURIComponent(document.cookie);
var ca = decodedCookie.split(';');
for(var i = 0; i < ca.length; i++) {
var c = ca[i];
while (c.charAt(0) == ' ') {
c = c.substring(1);
}
if (c.indexOf(name) == 0) {
return c.substring(name.length, c.length);
}
}
return "";
}
// Do not allow multiple call center tabs
if (~window.location.hash.indexOf('#admin/callcenter')) {
$(window).on('beforeunload onbeforeunload', function(){
document.cookie = 'ic_window_id=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;';
});
function validateCallCenterTab() {
var win_id_cookie_duration = 10; // in seconds
if (!window.name) {
window.name = Math.random().toString();
}
if (!getCookie('ic_window_id') || window.name === getCookie('ic_window_id')) {
// This means they are using just one tab. Set/clobber the cookie to prolong the tab's validity.
setCookie('ic_window_id', window.name, win_id_cookie_duration);
} else if (getCookie('ic_window_id') !== window.name) {
// this means another browser tab is open, alert them to close the tabs until there is only one remaining
var message = 'You cannot have this website open in multiple tabs. ' +
'Please close them until there is only one remaining. Thanks!';
$('html').html(message);
clearInterval(callCenterInterval);
throw 'Multiple call center tabs error. Program terminating.';
}
}
callCenterInterval = setInterval(validateCallCenterTab, 3000);
}

Categories

Resources