Because StorageEvent does not work here, I want to implement an event handler by localStorage.
Assume we have a web page as follows. Any change to the input field will trigger an event, we save the new value to localStorage. JSBin
<html ng-app="app">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.7/angular.min.js"></script>
</head>
<body ng-controller="Ctrl">
<input type="text" ng-model="text"></input>
<div id="console"></div>
<script>
var app = angular.module('app', []);
app.controller('Ctrl', ["$scope", function ($scope) {
$scope.$watch('text', function (newValue, oldValue) {
var x = "nV: " + newValue;
localStorage.setItem("messages", localStorage.getItem("messages") + " " + x)
debug(localStorage.getItem("messages"))
}, false)
}])
function debug(msg) {
document.getElementById("console").innerHTML += msg + "<br/>";
}
</script>
</body>
</html>
And we have another web page that listens. It scans localStorage by setInterval. It is actually a pipe: several messages can be stored in localStorage, and we should treat them all and then empty localStorage. JSBin
<html>
<body>
<div id="console"></div>
<script>
var listen = setInterval(function () {
var m = localStorage.getItem("messages");
if ((m !== "") && (m !== undefined)) {
localStorage.setItem("messages", "")
treatMessages(m);
}
}, 100)
function treatMessages(messages) {
debug(messages)
}
function debug(msg) {
document.getElementById("console").innerHTML += msg + "<br/>";
}
</script>
</body>
</html>
But what is important, is that we should make sure that no message is missed by the receiver. Unfortunately, it is not the case for the moment, For example, I typed quickly 123456789 in the input field, then 12345 was missing on the side of the receiver. It is probably because the sender generated 12345 just after the receiver read the localStorage and before the receiver emptied the localStorage.
So does anyone know how to fix this? Should we have a semaphore for localStorage or is there any other workaround?
Edit 1: I tried to add a semaphore by lock and waitfor: the sender and the receiver, but it still can miss messages. For example, 123456 is missing in the example below. It is not surprising, I think it is because when lock is free, we entered simultaneously the callback of the 2 waitfor, then it messed up.
Edit 2: I have done another shot which is supposed to work better, but I don't know why the two pages cannot align their localStorage value: the sender and the receiver
Try the newer IndexedDB. https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API/Using_IndexedDB. It is more sophisticated/complex. It is now broadly supported: http://caniuse.com/#search=indexeddb.
I believe it can solve your issue above (missed messages), but there is no changeEvent. I also believe it will not be able to see changes across browser (WebKit) instances on Mac (e.g. Excel for Mac) due to caching, but should work across tabs.
I suggest using localDataStorage to fire the events for you, for each key value addition, deletion or change. It even reports these events in a single page/tab! This utility can transparently set/get any of the following "types": Array, Boolean, Date, Float, Integer, Null, Object or String (no conversion needed).
[DISCLAIMER] I am the author of the utility [/DISCLAIMER]
Once you instantiate the utility, the following snippet will allow you to monitor the events:
function localStorageChangeEvents( e ) {
console.log(
"timestamp: " + e.detail.timestamp + " (" + new Date( e.detail.timestamp ) + ")" + "\n" +
"key: " + e.detail.key + "\n" +
"old value: " + e.detail.oldval + "\n" +
"new value: " + e.detail.newval + "\n"
);
};
document.addEventListener(
"localDataStorage"
, localStorageChangeEvents
, false
);
Related
My webpage is receiving through AJAX GET requests Arrays with strings, and a Boolean.
The objects within the array are displayed subsequently to shape a chat app, the received array represents messages to display in a chatbox. However, some of the messages have media in them.
Therefore, to recognize such message with image source in them, I added a Boolean Value (media=True : There is an image source).
With my current code, all arrays are testing their source in an empty <img src""> which creates a real mess on the chat box with unknown images. I need to be able to generate with JS an HTML image when an Object has a media = True with a source of 'mediasrc'.
AJAX Array in details
HTML:
<div id="display"></div>
JS:
<script>
$(document).ready(function() {
setInterval(function() {
$.ajax({
type: 'GET',
url: "/checkview",
success: function go(response) {
console.log(response);
$("#display").empty();
for (var model of response.models_to_return) {
var temp = "<div class='container darker'><b>" +
model.user_id + "</b><p>" +
model.room + "</p><span class='time-left'>" +
model.datetime + "</span><img src=../static/" +
model.mediasrc + ".png></div>";
$("#display").append(temp);
}
},
error: function(response) {
//alert('An error occured')
}
});
}, 1000);
})
</script>
By the way, this code works fine, but it's literally brute forcing all messages trying to fill an img:
while this is something that front-end frameworks handle particularly well, a common convention would be to split your template HTML. For example:
for (var model of response.models_to_return) {
var temp = "<div class='container darker'>"
+ "<b>" + model.user_id + "</b>"
+ "<p>" + model.room + "</p>"
+ "<span class='time-left'>" + model.datetime + "</span>";
if (model.media) {
//add img to template, could also check model.mediasrc != null
temp += "<img src=../static/" + model.mediasrc + ".png>"
}
temp += "</div>";
$("#display").append(temp);
}
If you want to write code up to the latest conventions, replace double quotes with back ticks, and reference variables with ${var_name}.
For example:
+ "<b>" + model.user_id + "</b>"
becomes:
+ `<b>${model.user_id}</b>`
Not 100% sure I understand the question, but you could create a utility function that takes the model and returns either the <img> markup or an empty string depending on whether model.mediasrc is present (or whatever condition is appropriate for your needs).
This probably isn't the exact implementation you need, but it demonstrates the pattern:
function imgMarkup (model) {
if (model.mediasrc) {
return `<img src="${model.mediasrc}" />`
}
return '';
}
for (var model of response.models_to_return) {
const temp=`
<div class='container darker'>
<b>${model.user_id}</b>
<p>${model.room}</p>
<span class='time-left'>${model.datetime}</span>
${imgMarkup(model)}
</div>`;
$("#display").append(temp);
}
i need to be able to capture user's password and then bypass it if user authorized with biometrics to Android WebView. I'm successfully capturing the password and passing it to the webview, I'm executing the js like this, the method returns me js with injected css selector and value to input which I run against the webview
fun getJsToEnterValueToTextField(cssSelectorById: String, value: String): String {
val js = "javascript:(function() { " +
"var element = document.getElementById(\"$cssSelectorById\");" +
"console.log(element);" +
"element.value='${value.trim()}';" +
" element.dispatchEvent(new Event('input', {\n" +
" view: window,\n" +
" bubbles: true,\n" +
" cancelable: true\n" +
" }))" +
"})()"
Timber.d("SWA_WEBVIEW - getJsToEnterValueToTextField >> $js")
return js
}
//--//
webview.loadUrl(url2load)
The problem happens if the user has any escape characters in the value,
for example if user has '%E9' as part of that password string, once I run that js > this %E9 would transform to é
Does anyone know if there is a way around it? I searched all over but nothing seems to make a difference.
I'm trying to detect acceleration of a mobile device. I've already tried using Accelerometer and now I'm also trying deviceMotionEvent. Whenever I print the properties event.acceleration.x, .y, or .z either in html or console, I'd get null. It would be much appreciated if anyone could help me see what I'm doing wrong. When I check sites in browser to see if my device can use accelerometer or deviceMotionEvent, it works there so it's not that my device can't handle it. Here's an iteration pieced together from many google searches I have from body:
<p id="test"> nothing </p>
<script>
function motion(event) {
document.getElementById("test").innerHTML = "acceleration x:" + event.acceleration.x;
console.log("Accelerometer: "
+ event.acceleration.x + ", "
+ event.acceleration.y + ", "
+ event.acceleration.z
);
}
if (window.DeviceMotionEvent) {
window.addEventListener("devicemotion", motion, false);
document.getElementById("test").innerHTML = "eventlistner added"
} else {
document.getElementById("test").innerHTML = "sadness it won't work";
console.log("DeviceMotionEvent is not supported");
}
</script>
The text on the doc ends up being "acceleration x:null". Insight is appreciated. Thank you!
I am trying to create code that when you press a button, it will change the value of a variable and replace some text.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<p id="unitts">You have 0 unitts</p>
<script type="text/javascript">
var unitt = 0;
function unittIncrease() {
var unittPrev = unitt;
unitt++;
document.getElementById(unitts).innerHTML.replace("You have " + unittPrev.toString() + " unitts.", "You have " + unitt.toString() + " unitts.");
}
</script>
<button id="unittIncrease" onclick="unittIncrease();">Digitize Unitt</button>
</body>
</html>
When I press the button, nothing happens to the text.
I don't know why this does not work.
Please help me!
EDIT: I am only 11 years old,
please don't throw your wizard
code at me.
maybe you should remove your button system and add a while loop that
automatically add a unit but waits one second with a setInterval
function
I think you should write the js code like this
document.getElementById('unitts').innerHTML = "You have"....
Instead of:
document.getElementById(unitts).innerHTML.replace("...")
Your JavaScript should be (note the unitts wrapped in quotes and the full stop removed):
document.getElementById('unitts').innerHTML = "You have " + unitt + " unitts";
Instead of:
document.getElementById(unitts).innerHTML.replace("You have " + unittPrev.toString() + " unitts.", "You have " + unitt.toString() + " unitts.");
In the latter, it is looking for the non-existent variable unitts instead of the string 'unitts'. Also, you are looking for the text You have x unitts. which cannot be found because in your HTML, it is just You have x unitts without the full stop.
Edit
See this plnkr.
Apart from the issues that the other answer mentions, by calling .replace method on the .innerHTML property of the element, the content of it doesn't change. You should reset the property by using the returned value of the method call:
el.innerHTML = el.innerHTML.replace(...);
Also, as you are trying to increase a number, instead of replacing all the characters, you can just replace the numeric part:
var unitts = document.getElementById('unitts');
function unittIncrease() {
unitts.textContent = unitts.textContent.replace(/\d+/, function(n) {
return +n + 1;
});
}
https://jsfiddle.net/h6odbosg/
thanks for having a look at my question,
I am trying to set up custom events (Analytics tracking) using the jQuery.tubeplayer.js plugin at http://www.tikku.com/jquery-youtube-tubeplayer-plugin#tubeplayer_tutorial_3
I can get the plugin working and attach events to onPlayerPlaying, onPlayerPaused,onPlayerEnded etc but cannot extract the data I want to pass to the event. I want to extract the URL of the video and the time of the video when the event is triggered. This data can be extracted from the video using the showData(jQuery('#youtube-player-container').tubeplayer('data')); function in the example, I cant seem to get this data into my event.
My code is as follows:
<script type="text/javascript" src="js/jquery.min.js"></script>
<script type='text/javascript' src='js/jQuery.tubeplayer.js'></script>
</head>
<body>
<div id='youtube-player-container'> </div>
<a onClick="showData(jQuery('#youtube-player-container').tubeplayer('data'));" href="javascript:void(0);">Click here to see data</a>
<div class="EventListener">The is the initial event listener text</div>
<a onClick="showVideoURL(jQuery('#youtube-player-container').tubeplayer('data'));">Click to see the URL of the video</a><br/>
<span class="VideoURL"></span><br/>
<div class="Bufferstatus">The is Buffertext</div>
<a onClick="showTime(jQuery('#youtube-player-container').tubeplayer('data'));">Click to see the time of the video</a><br/>
<span class="currentTime"></span><br/>
<script>VideoID="i3AqF9e8WV4"</script>
<script src="js/jQuery.tubeplayer.settings.js"></script>
with the script tubeplayer settings at
var url=location.href;
jQuery.tubeplayer.defaults.afterReady = function(){
//jQuery("#player").tubeplayer("cue", " ");
};
initPlayer();
function showData(data){
var html = "bytesLoaded : " + data.bytesLoaded;
html += " / bytesTotal : " + data.bytesTotal + "\n";
html += "currentTime : " + data.currentTime;
html += " / duration : " + data.duration + "\n";
html += "startBytes : " + data.startBytes + "\n";
html += "state : " + data.state + "\n";
html += "quality : " + data.availableQualityLevels.join(",") + "\n";
html += "url : " + data.videoURL + "\n";
html += "videoID : " + data.videoID;
alert(html);
}
function showTime(data){
$('.currentTime').text('The time when clicked was:' + data.currentTime);
}
function showVideoURL(data){
$('.VideoURL').text('The video URL is:' + data.videoURL);
}
showData(jQuery('#youtube-player-container').tubeplayer('data'));
function initPlayer(){
jQuery("#youtube-player-container").tubeplayer({
initialVideo: VideoID,
width: 600,
height: 450,
onPlayerPlaying: function(){$('.EventListener').text('The video is played at' + data.currentTime);},
onPlayerPaused: function(){$('.EventListener').text('The video is paused at' + data.currentTime);},
onPlayerEnded: function(){$('.EventListener').text('The video ended');},
onPlayerBuffering: function(){$('.Bufferstatus').text('The video is buffering');},
modestbranding: false,
showControls: 1,
onQualityChange: function(quality){$('.qualityCheck').text('The quality of the video is: ' +quality);}
});
};
The specific data is would like is the video URL, the time at which the event took place if possible. The data shows in the pop up when the tags are clicked.
Any help is greatly appreciated.
Thanks,
Simon
You should invoke $("#youtube-player-container").tubeplayer("data") every time you want to get information from the player. This is to ensure that you get the most up to date information.
The code inside of the onPlayerX events doesn't make any sense:
$('.EventListener').text('The video is played at' + data.currentTime);
since the 'data' object doesn't refer to anything.
Instead of using 'data.currentTime', use:
$("#youtube-player-container").tubeplayer("data").currentTime
and that should take care of your issue.
Alternatively, since you have setup the 'showTime' and 'showVideoURL' functions that take a data object, you can pass the .tubeplayer("data") object into those methods, like:
showTime( $("#youtube-player-container").tubeplayer("data") )
similarly to how showData is being used before initPlayer is defined.
Does that help?