I have a weird problem.
I try to write a GreaseMonkey script to be run in Firefox and Google Chrome.
With Chrome I tried 2 extensions : "TamperMonkey" and "Blank Canvas Script Handler", mainly because my script check regulary for a new version on an external site and this is considered as cross site scripting and not authorized in Chrome.
To show you my problem, I write a simple test case :
// ==UserScript==
// #name test
// #namespace http://fgs.ericc-dream.fr.nf
// #description test gm script
// #include http://gaia.fallengalaxy.eu/
// #author ericc
// #version 0.0.1
// ==/UserScript==
/* We attach an event listener to the body tag and trigger the function
* 'message' each time that an element is inserted in the page */
var el = document.body;
el.addEventListener('DOMNodeInserted', message, false);
var extraFlag = false;
function message(event) {
/* first we capture the id of the new inserted element
* (the one who created the event) */
var objId = event.target.id;
/* add an event listener on the map container */
if (objId == "extra") {
el = document.getElementById('extra');
el.addEventListener('DOMSubtreeModified',readTest,false);
GM_log(el.style.display);
}
}
function readTest() {
el = document.getElementById('extra');
GM_log(extraFlag);
GM_log(el.style.display);
if ((el.style.display != 'none') && (!extraFlag)) {
alert('extra');
extraFlag = true;
} else if ((el.style.display == 'none')) {
extraFlag = false;
}
}
the div element 'extra' is modified by the page. The problem is that Chrome is unable to read the value of el.style.display and thus extraFlag never become 'false' again.
I use this flag to avoid to run the code several time, the site is heavily JavaScript driven
This code work nicely in Firefox !
I tried to search with Google but can't find a correct answers. Seems easy to change the value of display, but it seems that I'm the only one who try to read it !!!
I write this code because "DOMAttrModified" isn't supported in Chrome :-(
Thanks in advance for your help
ericc
I'm having a hard time understanding exactly what your question is, but it looks like Chrome can read .style.display properties just fine. I just threw the following code into an HTML template and loaded it in Chrome 10:
<div id="div1">
</div>
<div id="div2" style="display: block;">
</div>
<div id="div3" style="display: inline;">
</div>
<div id="div4" style="display: none;">
</div>
<script type="text/javascript">
alert(document.getElementById("div1").style.display);
alert(document.getElementById("div2").style.display);
alert(document.getElementById("div3").style.display);
alert(document.getElementById("div4").style.display);
document.getElementById("div1").style.display = "none";
alert(document.getElementById("div1").style.display);
</script>
The code produced 5 'alert' boxes with the following output:
blockinlinenonenone
So it seems Chome reads this property just fine.
Maybe the issue is that the webpage on which you're running your greasemonkey script is behaving differently in Chrome than in Firefox? Could it be that the ID of the element is different, or the element is being removed from the DOM instead of just being hidden? What would happen if you modified your function with some more checks, kinda like this?
function readTest() {
el = document.getElementById('extra');
if(el)
{
GM_log(extraFlag);
GM_log(el.style.display);
if (el.style.display && (el.style.display != 'none') && (!extraFlag)) {
alert('extra');
extraFlag = true;
} else if ((el.style.display == 'none') || !el.style.display) {
extraFlag = false;
}
}
else
{
GM_log(extraFlag);
GM_log("element not present");
extraFlag = false;
}
}
Does that help? If not, is there any other reason you could think of why el.style.display wouldn't evaluate properly in Chrome?
It might help if we knew more about what you're trying to do with your script, and possibly what web page or code you're trying to run this on.
After several hours and a ton of test case, I finally find an acceptable explanation (but not yet a solution !)
Let's explain the scenario :
1°) the user click on an icon on the screen
2°) the div#extra, which is already present in the page, is made visible by removing its display property (.style.display="")
3°) the div#extra is filed by an AJAX function with some elements depending on which icon was clicked by the user (more than 200 elements in certain case)
4°) the user click on an other icon to close the div
5°) all elements from the div#extra are removed
6°) the div#extra is hidden by putting is display property to 'none' (.style.display="none")
At first, on Firefox, I used "DOMAttrModified" event on the div#extra to check when the display property was modified and react accordingly.
Problem, this event is not supported on Chrome !!
So I replace it by "DOMSubtreeModified" (attached to div#extra) which is supported by both browser .... but not exactly in the same way :-(
On Firefox, an event is fired for every modification in the subtree but also when the element itself is modified.
On Chrome, they are a little bit more strict and fired event only for modification in the subtree .... and this is my issue !
In Firefox,first event is fired at point 2 (in the scenario) and last at point 6 allowing my function to read when the div#extra is made hidden
In Chrome, first event is fired at point 3 and last at point 5 ... so when the the div#extra is hidden my function is not called and I can't modify the flag !!!! CQFD
Now, or I will add an event listener to the body of the page to intercept when the display property is modified, but it will generate a lot of call to my function, or the developer of TamperMonkey said yesterday that his extension now support "DOMAttrModified" (on Chrome) ....
Thanks anyway to take the time to understand my question and your proposed solution
ericc
Related
I got a warning by my ad system provider about click fraud. No further info, all they are recommending is "hide the ads for users who click on ads too quickly'". I wrote a piece of JS script that hides all DIVs with ads for N seconds (using cookie) when clicked on, but this solution does not work as the "inner" content (with ads) is generated by an JS script that calls and renders the content from external server (as you would expect from an ad system). So, when one takes the cross-domain security into account it is kinda Catch 22. How can I detect a click inside a DIV (locally defined) of which content is rendered by an external JS and in iframe?
Example:
<div class="ad-class"> <!-- locally defined div -->
<div id="my-id"> </div> <!-- identifies my ad in the provider's system -->
<script>
var foo = blah // declares the ad dimensions and stuff
// and renders the contextual ad in #my-id DIV
</script>
</div>
Were it all local, solution would be easy as the internal div would inherit the parent class ("ad-class"). In case of cross-domain, this is not valid. Any tips, dudes?
You cannot detect click events in cross-domain iframe.
That put, you might have one bad option:
One of the nearest things you can do is detect that the focus moved from your window to the iframe:
window.focus(); //force focus on the currenct window;
window.addEventListener('blur', function(e){
if(document.activeElement == document.querySelector('iframe'))
{
alert('Focus Left Current Window and Moved to Iframe / Possible click!');
}
});
http://jsfiddle.net/wk1yv6q3/
However it's not reliable, loose focus does not mean a click, it could be user moving across the website using TAB.
Another problem is that, you only detect the first time focus is moved to the iframe, you do not know what user does in there, he can click a million times and you will never know.
Luizgrs inspired me this solution :
var clickIframe = window.setInterval(checkFocus, 100);
var i = 0;
function checkFocus() {
if(document.activeElement == document.getElementById("ifr")) {
console.log("clicked "+(i++));
window.focus();
}
}
<!DOCTYPE html>
<h2>Onclick event on iframe</h2>
<iframe src="https://www.brokenbrowser.com/" id="ifr"></iframe>
The function detect if the iframe has the focus, if yes, the user clicked into the iframe. We then give back the focus to our main windows, which allow us to find if the user click another time.
This trick has been usefull to me for a POC on a 2 step iframe click-jacking. Getting to know when the user clicked for the first time on the iframe allowed me to reorganize my different layers to keep the illusion perfect.
The approach #Luizgrs pointed out is very accurate, however I managed to indeed detect the click event using a variation of the method:
var iframeMouseOver = false;
$("YOUR_CONTAINER_ID")
.off("mouseover.iframe").on("mouseover.iframe", function() {
iframeMouseOver = true;
})
.off("mouseout.iframe").on("mouseout.iframe", function() {
iframeMouseOver = false;
});
$(window).off("blur.iframe").on("blur.iframe", function() {
if(iframeMouseOver){
$j("#os_top").click();
}
});
The above code works like a charm on desktop if you want to add mobile support you just need to use touch events touchstartand touchendevents to simulate the mouseover on mobile.
Source
Well, a while ago I found this plugin for WordPress. Obviously it does what I need -- just wondering how this guy made it to work, it does count clicks on Adsense iframe. I must have a closer look though I am not a PHP programmer. I program mainly in Python and need some solution of this kind for Django. If anyone can read the code easily, I would appreciate any help.
The plugin is searching first for any iframe wrapped by a previous specified class name.
The iframe id´s will be collected in a array and for everyone of these id´s an mouseover event will be created which fires the script which hides the class 'cfmonitor'. As a result the iframe containing ad is not visible anymore.
// IFRAME ACTION
function iframeAction () {
jq.each(jq.cfmonitor.iframes, function(index,element) {
frameID = jq(element).attr('id') || false;
if (frameID) initiateIframe(frameID);
//alert (frameID);
});
}
// INIT IFRAME
function initiateIframe(elementID) {
var element = document.getElementById(elementID);
// MOUSE IN && OUT
if (element) {
element.onmouseover = processMouseOver;
element.onmouseout = processMouseOut;
//console.log("mouse on out");
}
// CLICKS
if (typeof window.attachEvent !== 'undefined') {
top.attachEvent('onblur', processIFrameClick);
}
else if (typeof window.addEventListener !== 'undefined') {
top.addEventListener('blur', processIFrameClick, false);
}
}
// IFRAME CLICKS
function processIFrameClick() {
// ADD A CLICK
if(isOverIFrame) {
//addClick();
// Some logic here to hide the class 'cfmonitor'
//console.log("Go");
top.focus();
}
}
Check this it might help. You can not detect the click event when its cross browser.
window.focus();
window.addEventListener('blur', function(e){
if(document.activeElement == document.getElementById('Your iframe id'))
{
console.log('iframe click!');
}
});
I am trying to resolve a "browser compatibility" issue on our old website, which has a lot of javascript, css and html. they are asp pages, but I'm evaluating what actually is getting sent to the browser.
We have a page that has several text boxes (html input element of type=text) that you can't type into them unless you are on IE 7. Newer versions of IE and other modern browsers, when you click on the text box, you don't even get the flashing I beam cursor. But it momentarily flashes the border.
In Chrome, I right clicked and did Inspect Element, and I removed the text boxes class and all event handlers and the problem remained. Then I inspected the usual suspects: read-only, disabled, enabled, max-length, and they are all unrestricted.
What other DOM properties or style attributes can I check? Should I not assume that just because I removed html in Chrome inspect elements tab, it took effect?
I'm just looking for a list of weird things to check since I'm not primarily a web developer. The fact that it works in an older browser but no newer browsers makes me think that some html, css or javascript has come to be interpreted differently or additional things are being handled that were not handled before. Perhaps the newer browsers have uncovered (brought to the surface) some bad / illogical code.
EDIT:
Here is a fiddle that reproduces the problem, at least in Chrome:
http://jsfiddle.net/2n2sJ/6/
<input type="text"/>
var ns6 = document.getElementById && !document.all
var isMenu = false;
var menuSelObj = null;
var overpopupmenu = false;
function mouseSelect(e) {
var obj = ns6 ? e.target.parentNode : event.srcElement.parentElement;
if (isMenu) {
if (overpopupmenu == false) {
isMenu = false;
overpopupmenu = false;
document.getElementById('menudiv').style.display = "none";
document.getElementById('Div1').style.display = "none";
return true;
}
return true;
}
return false;
}
document.onmousedown = mouseSelect;
When a click or focus event is handled by javascript, and the javascript returns false, this will make the text box appear to be disabled.
Have the handler return true instead of false to allow the event to occur.
I'm writing a website with a canvas in it. The website has a script that runs successfully on every refresh except for a line at the end. When the script ends with:
document.body.onresize = function() {viewport.resizeCanvas()}
"document.body.onresize" is unchanged. (I double-checked in Chrome's javascript console: Entering "document.body.onresize" returns "undefined".)
However, when the script ends with:
document.body.onresize = function() {viewport.resizeCanvas()}
console.log(document.body.onresize)
"document.body.onresize" does change. The function works exactly as it should.
I can't explain why these two functionally identical pieces of code have different results. Can anyone help?
Edit: As far as I can tell, "document.body" is referring to the correct "document.body". When I call console.log(document.body) just before I assign document.body.onresize, the correct HTML is printed.
Edit 2: A solution (sort of)
When I substituted "window" for "document" the viewport's "resizeCanvas" function was called without fail every time I resized the window.
Why does "window" work while "document" only works if you call "console.log" first? Not a clue.
Resize events: no go
Most browsers don't support resize events on anything other than the window object. According to this page, only Opera supported detecting resizing documents. You can use the test page to quickly test it in multiple browsers. Another source that mentions a resize event on the body element specifically also notes that it doesn't work. If we look at these bug reports for Internet Explorer, we find out that having a resize event fire on arbitrary elements was an Internet Explorer-only feature, since removed.
Object.observe: maybe in the future
A more general method of figuring out changes to properties has been proposed and will most likely be implemented cross-browser: Object.observe(). You can observe any property for changes and run a function when that happens. This way, you can observe the element and when any property changes, such as clientWidth or clientHeight, you will get notified. It currently works only in Chrome with the experimental Javascript flag turned on. Plus, it is buggy. I could only get Chrome to notify me about properties that were changed inside Javascript, not properties that were changed by the browser. Experimental stuff; may or may not work in the future.
Current solution
Currently, you will have to do dirty checking: assign the value of the property that you want to watch to a variable and then check whether it has changed every 100 ms. For example, if you have the following HTML on a page:
<span id="editableSpan" contentEditable>Change me!</span>
And this script:
window.onload = function() {
function watch(obj, prop, func) {
var oldVal = null;
setInterval(function() {
var newVal = obj[prop];
if(oldVal != newVal) {
var oldValArg = oldVal;
oldVal = newVal;
func(newVal, oldValArg);
}
}, 100);
}
var span = document.querySelector('#editableSpan');
// add a watch on the offsetWidth property of the span element
watch(span, "offsetWidth", function(newVal, oldVal) {
console.log("width changed", oldVal, newVal);
});
}
This works similarly to Object.observe and for example the watch function in the AngularJS framework. It's not perfect, because with many such checks you will have a lot of code running every 100 ms. Additionally any action will be delayed 100 ms. You could possibly improve on this by using requestAnimationFrame instead of setInterval. That way, an update will be noticed whenever the browser redraws your webpage.
What you can do is that if you know for certain what particular action triggers a resize on your element that doesn't resize the full window you can trigger a resize event so your browser recalculate all of the divs (if by the case the browser is not triggering the event correctly).
With Jquery:
$(window).trigger('resize');
In the other hand, if you have an action that resizes an element you can always hold from that action to handle other following logic.
<script>
function body_OnResize() {
alert('resize');
}
</script>
<body onresize="body_OnResize()"></body>
Okay i know this has been asked a lot but it seems that none of the solutions actually work for me. Here's the situation. I have a webpage that i need to add to an existing site, this site uses a master page which i can not touch. This limits me to using javascripts window.onload because i do not have access to the body tag.
On my page i have linked my external .js file in the head beneath every other external file. Here is an example of what my .js file looks like.
var myobj = null;
(5 or so functions that work properly. Mainly just toggles that show and hide divs. none touch the onload)
function load(){
myobj = document.getElementById("my_element");
alert("test");
}
window.onload = load;
Tried this and the load function never fires as i never get the alert. I've tried commenting out the first line in the load function and only haven't the alert and still nothing. Looking around i also found another way to do it that i tried without success. Everything else is the same except i removed the window.load and added this.
function addLoadEvent(func) {
var oldonload = window.onload;
if (typeof window.onload != 'function') {
window.onload = func;
} else {
window.onload = function () {
if (oldonload) {
oldonload();
}
func();
}
}
}
addLoadEvent(load);
addLoadEvent(function () {
/* more code to run on page load */
alert("hello2");
});
In this function, neither of the alerts fire. I have also tried placing an alert outside of a function, that one does work.
The browsers i am using are IE 8.0.7600.16385 and Chrome 21.0.1180.60
Let me know if you need more information.
Oh and as a side note, i cannot use jquery or any other javascript library as we are trying to keep this as light as possible. This page also must work in IE8, that is the businesses only supported browser at the moment. It would be nice if it worked in Chrome as well.
EDIT
In case i'm going about this completely the wrong way, what i am trying to do is keep track of the last element i have. I essentially have a page with 2 columns, left side is a menu and right is content. The content is all placed in div's with only one category showing at a time. The way it is supposed to work is when clicking on the menu category it hides the previous content and shows the new content.
I have set my content class to display: none; and have the start_content ID set to display: block;. What the Javascript is supposed to do is initialize my global with the start_content object. When clicking in the menu it calls a function that does an obj.style.display = 'none' and then sets the new obj to display = 'block'. It then takes the new obj and places it in my global variable to be changed on the next menu click.
here's an example without any of the onload functions
var prevContent = document.getElementById("start_content");
function toggle(id) {
prevContent.style.display = "none";
var content = document.getElementById(id);
content.style.display = "block";
prevContent = content;
}
The problem with this is that prevContent is unidentified when it enters the toggle function. I had assumed this was because i am linking this .js file in the head and so the page hasn't loaded my start_content yet which is why i had changed it to declaring the global as a null and then setting up a window.onload to set the appropriate value after it is created.
Adding "Defer" to the script tag in the head ended up doing the trick.
I am trying to dynamically load a coverflow type object (think itunes coverflow but less fancy) on a button click after the webpage has already loaded. I am dynamically creating a list of images to feed to the javascript for the coverflow that then loads them and does it's magic to make it look pretty. The problem is that in firefox the code is working, but in chrome and ie (surprise surprise) the javascript is throwing an error and the page is going blank due to the error throw below. The problem is in this block of code that is trying to capture the dom element by id
if (typeof(this.Container) == 'string') { // no node
var container = document.getElementById(this.Container);
if (container) {
this.Container = container;
} else {
throw ('ContentFlow ERROR: No element with id \''+this.Container+'\' found!');
return;
}
}
Pretty much in chrome the dome element is not captured by the code up above when it is definitely available in the page. I even typed out document.getElementById("container_name"); in the console of chrome and it returned the element so I am clueless as to whey it won't work in the file.
Any suggestions would be appreaciated
Thanks
EDIT:
here is the onpage html that is trying to be filled
<div id="contentFlow" class="cool_ui ContentFlow">
<p id="coverflow_school_name"></p>
<div class="loadIndicator"><div class="indicator"></div></div>
<div class="flow" style="height:240px;"></div>
<div class="scrollbar">
<div class="slider"></div>
</div>
</div>
ANSWERED:
Wow, ok. I figured it out. The problem was the way some resources were being dynamically loaded before the call to that piece of code. The resource loading was causing the page to go blank, thus making var container = document.getElementById(this.Container); return null hence the exception being thrown. Weird part was firefox could handle the resource loading, but chrome could not.
Thanks for the help
Why would you not use jquery?
$('#container_name')
UPDATE: on second reading, is this the name or the Id of the element?
If it is name thenn use
$('[name="container_name"]')
Using JQuery you can just say
if($(this.Container).length){
//Code goes here
}
else
{
throw ('ContentFlow ERROR: No element with id \''+this.Container+'\' found!');
return;
}
I tried the code in Chrome 12.0.742.112 and it seems to work fine. Here is a link: http://jsfiddle.net/eemYg/.
I presume another thing is causing the problem, for example this.Container. You should check it's value (in Chrome) and see if it has a different value than the one in Firefox.