I want to develop chrome extension to put a check on the script say this website runs http://whatsmyscreenresolution.com/
e.g.
if (his_script==my_script)
then
block it or return "123".
I want to do something like this.Is it possible or can I even block websites to detect my screen resolution, font, etc other than disabling javascript at my end?
can I even block websites to detect my screen resolution
You could define a new window.screen object
(function (screen) {
function clone(e) {
var o = {}, k;
for (k in e) o[k] = e[k];
return o;
}
Object.defineProperty(window, 'screen', {get: function () {
var o = clone(screen);
o.availHeight = o.height = Math.random() * (o.height - 600) + 600;
o.availWidth = o.width = Math.random() * (o.width - 600) + 600;
return o;
}});
}(window.screen));
After this, trying to access screen or window.screen will give you randomised (but not entirely unreasonable for styling purposes) values
DEMO
Take a look at the chrome.webRequest api: https://developer.chrome.com/extensions/webRequest
Theoretically, you could do this with the onBeforeRequest listener.
It doesn't think it's possible. Tried setting window.screen and creating a var screen but no matter what is written to screen.width and screen.height it always returns the correct resolution. It doesn't seem spoofable at least from a javascript console. You might try a hidden frame with the desired screen resolution for privacy and when the page is loaded adjust the resolution to actual browser resolution and display the frame.
Related
Short Question
How can I (as reliably as possible) calculate the time when "above the fold" content is visually complete, including external CSS and fonts being applied and any images loaded.
Full Question
Apologies there is a lot to this question, I just wanted to show I had worked on the question and where I was at so it didn't end up as a "how do I do this" type question and get insta closed!!
I am attempting to try and work out if all resources required to render "above the fold" content have been fully downloaded in the client browser.
This is part of a bigger goal of simulating SpeedIndex purely using browser APIs (i.e. not using a screenshot timeline).
What I need to gather
All of the elements that appear above the fold on a page.
Ensure that all relevant assets have loaded.
Additionally this data is being sent to the server for analysis so I want to try and keep it at one request if possible.
Challenges I can't overcome
Having to run the function that gets the elements above the fold more than once
Ensuring that all critical assets are actually loaded on a very slow connection.
Making sure the function does run if network traffic is high, if there is never a quiet 2 second window on the network (maybe due to an old fashioned chat that polls the server every second) it will never fire.
Firstly this doesn't have to be perfect, it is an approximation, but the more accurate I can make it the better!
The way I am doing it at the moment is using PerformanceObserver to list all resources as they are downloaded.
The second I get a 2 second window where no requests have been completed I assume critical CSS has been downloaded and start looking at the images on the page.
//getRects is the function to get all of the rectangles above the fold.
var rectInterval = setTimeout(getRects, 2500);
var xx = new PerformanceObserver(function (ll, p) {
ll.getEntries().forEach(function (en) {
if (en.name.indexOf(apiEndpoint) == -1) {
if (en.entryType == "layout-shift") {
if (en.entryType == "resource"){
//any resources I reset the timer waiting for a quiet time
clearTimeout(rectInterval);
rectInterval = setTimeout(getRects, 2000);
}
}
});
});
xx.observe({
entryTypes: ['largest-contentful-paint', 'longtask', 'resource', 'paint', 'navigation', 'mark', 'measure', 'layout-shift', 'first-input']
});
I grab the dimensions of all images and elements with background images on the page in the function getRects using getBoundingRect() and then calculate if they appear above the fold using window.innerHeight etc.
These are the candidates to check when they downloaded (along with the previous list of resources etc.)
var doc = window.document;
var browserWidth = window.innerWidth || doc.documentElement.clientWidth;
var browserHeight = window.innerHeight || doc.documentElement.clientHeight;
function checkRectangle(el){
var rtrn = false;
if (el.getBoundingClientRect) {
var rect = el.getBoundingClientRect();
//check if the bottom is above the top to ensure the element has height, same for width.
//Then the last 4 checks are to see if the element is in the above the fold viewport.
if (rect.bottom <= rect.top || rect.right <= rect.left || rect.right < 0 || rect.left > browserWidth || rect.bottom < 0 || rect.top > browserHeight) {
rtrn = false;
}else{
rtrn = {};
rtrn.bot = rect.bottom;
rtrn.top = rect.top;
rtrn.left = rect.left;
rtrn.right = rect.right;
}
}
return rtrn;
}
//function to get the rectangles above the fold
function getRects(){
var rects = [];
var elements = doc.getElementsByTagName('*');
var re = /url\(.*(http.*)\)/ig;
for (var i = 0; i < elements.length; i++) {
var el = elements[i];
var style = getComputedStyle(el);
if(el.tagName == "IMG"){
var rect = checkRectangle(el);
if(rect){
//The URL is stored here for later processing where I match performance timings to the element, it is not relevant other than to show why I convert the `getBoundingClientRect()` to a simple object.
rect.url = el.src;
rects.push(rect);
}
}
//I also need to check for background images set in either CSS or with inline styles.
if (style['background-image']) {
var rect = checkRectangle(el);
if(rect){
var matches = re.exec(style['background-image']);
if (matches && matches.length > 1){
rect.url = matches[1].replace('"', '');
rects.push(rect);
}
}
}
}
That bit is fine (although any tips to narrow the search so I am not looping over everything would be great) but my problem comes on a slow loading website. If there is more than a 2 second gap between requests (which can happen on a particularly slow connection or if the server is a long way from the user) then I won't get complete data.
My workaround was to then monitor for further network requests (yet again waiting for a 2 second delay between requests) and re-run the function to gather the above the fold content. This obviously does not work well if the site uses lazy loading on scroll as requests can keep firing throughout the page lifecycle.
As gathering the dimensions of the elements can be quite CPU intensive on a very heavy page, coupled with the need to send this data to the server for analysis, I am trying to find a more robust way of ensuring all critical content is loaded. or a way to only fire getRect once but ensure all initial loading is complete.
Presume that any manipulation of data can be done later on the server if the payload is small enough (less than 1kb say)
Things I have considered
Looking for any <links>, <scripts> etc. and checking they have loaded. The problem comes with dynamically added links as well as external resources (i.e. stylesheets linked within another stylesheet). This would probably be more robust but would become very complex.
Setting the time between checks (the quiet time I am waiting for) to be higher. This obviously makes the problem of a traffic heavy website worse as the "quiet time" may never occur.
Using MutationObserver to monitor the page and yet again waiting for quiet time. However this would get fired more often if the page had any interactivity as far as I can tell?
I am aware that my method will over report for sites that have correctly inlined their CSS, that is not a problem.
Am I on the right track as a way of solving this conundrum, or is there some easy formula I can use based on window.performance data (or similar API) that lets me say "all above the fold elements are loaded and rendered."
I hope that is clear but any questions just ask as I know there is a lot in this question to answer simply "how do I check all critical resources have loaded".
My page opens a popup and communicates with it using window.postMessage. To know when it is ready, one of the first things in the popup-script is:
window.opener.postMessage("initialize")
and then I reply and give the data and so on.
However if I have two instances of the same page open I'm running into a few problems. In Chrome and Firefox it actually opens individual popups even when the windowName is set. Setting focus using myPopup.focus() doesn't even seem to bring them up to the top. In IE however it reuses the same window, which I initially thought was a great improvement.
As stated in the spec, the window.opener reference is however never updated, even when another parent reopened it. Meaning the initial code will communicate with my first instance. I've tried in various ways to change the behavior, but I can't seem to communicate between these in any way.
Then I found a clever way of detecting this, storing the dimensions and position, then closing and reopening it. It looks like this:
const createPopup = (dimensions) => {
let features = "menubar=0,toolbar=0,status=0,personalbar=0,location=0,resizable=1,scrollbars=1";
const myPopup = window.open("/imageViewer.html", "ImageViewer", features);
if (myPopup.opener !== window) {
dimensions = { height: myPopup.outerHeight, width: myPopup.outerWidth, X: myPopup.screenX, Y: myPopup.screenY };
myPopup.close();
return createPopup(dimensions);
}
if (dimensions) {
myPopup.moveTo(dimensions.X, dimensions.Y);
myPopup.resizeTo(dimensions.width, dimensions.height);
} else {
myPopup.focus();
}
return myPopup;
};
The problem is that the main use I have for this is when the popup is located on a secondary monitor, and it doesn't seem to be allowed to neither move the popup outside the dimensions of the primary screen.
Is there anyway to solve this problem with using postMessage? My only other alternative which comes to mind is using localstorage to put information and look this up on intervals, but I'm not very happy with such a solution.
So to sum up I need to have a function (createPopup) which will create or bring a secondary window/popup to the front. The main window needs to be able to communicate with it, and it must work when using different instances of the same main page. (but running the function again when switching instances is OK.)
While setting in JavaScript failed, it works when setting directly when opening the window in the features-parameter:
export const createPopup = (dim) => {
let features = "menubar=0,toolbar=0,status=0,personalbar=0,location=0,resizable=1,scrollbars=1";
if (dim) {
features += ",left=" + dim.X + ",top=" + dim.Y + ",width=" + dim.width + ",height=" + dim.height;
}
const myPopup = window.open("/imageViewer.html", "ImageViewer", features);
try {
if (myPopup.opener !== window) {
throw Error("just trying to read opener will throw exception in IE if the opening window has been closed");
}
} catch {
dim = { height: myPopup.outerHeight, width: myPopup.outerWidth, X: myPopup.screenX, Y: myPopup.screenY };
myPopup.close();
return createPopup(dim);
}
myPopup.focus();
return myPopup;
};
Focus still doesn't seem to work in chrome-based browsers, but that is a very different bug indeed.
I am trying to right a script that will resize images as the browser window scales. However, I get this error in the console when I refresh the site:
TypeError: Cannot read property 'offsetWidth' of null
In addition, if there is a function which is called every time the user resizes the window, that would be useful as well. Here is my javascript:
`var skill_logos = [],
console,
skill_logos_container = document.getElementById("skills-container"),
code_logo = document.getElementById("code-logo"),
design_logo = document.getElementById("design-logo"),
profile_picture = document.getElementById("profile-picture"),
school_logo = document.getElementById("school-logo"),
tech_logo = document.getElementById("tech-logo");
skill_logos = [code_logo, design_logo, profile_picture, school_logo, tech_logo];
function update() {
"use strict";
var i = 0;
for (i = 0; i < skill_logos.length; i = i + 1) {
skill_logos[i].offsetHeight = skill_logos[i].offsetWidth * skill_logos_container.offsetWidth / skill_logos_container.offsetHeight;
console.log("Yes!");
}
}
update();
setInterval(update(), 5000);`
Any help would be greatly appreciated. Thanks in advance.
I recommend you to use css not js !
What you are trying to do can be easily done using css :
<img src="logo.jpg" style="min-width:5%;max-width:5%;">
Percent in css means percent of current page size, so in this case combining min and max width always get 5% of your page width for logo image
To assign your function to be called on window resize, do the following:
window.onresize = update;
As other commentators have noted, the null error is most likely occurring because the element doesn't exist at the time it's being called. Use a tool like the Chrome debugger to ensure the DOM is in the state you think it is when the function is being called
I am using ui-screen-shooter, which makes use of the UI Automation JavaScript API to take screenshots of apps. My app has a slightly different structure on iPad and iPhone, so I need to detect the device type in my shoot_the_screen.js script and run different code. I would like something equivalent to [[UIDevice currentDevice] userInterfaceIdiom] that I can use in JavaScript. Here is the best I have come up with. It works, but do you know of a cleaner, less device-dependent way to get the same information?
var target = UIATarget.localTarget();
var width = target.rect().size.width;
if (width == 1024 || width == 768)
{
// iPad
}
else
{
// iPhone
}
You can call model() on the target to get the information you need. That's exactly what I'm doing in the ui-screen-shooter itself.
var modelName = UIATarget.localTarget().model();
// This prints "iPhone" or "iPad" for device. "iPhone Simulator" and "iPad Simulator" for sim.
UIALogger.logMessage(modelName);
I have a case where I'd like to animate the zoom style of a div (and it's entire contents). Legibility is not an issue, as this will be to 'pop' the element into view. Now I can get just about every other style aspect animating with Fx, but I can't seem to get this working for the zoom.
This is in chrome (though obviously I want to get it browser agnostic as well).
Using the Elements tab in the Chrome dev tools I can manually set the zoom style on the html element and it behaves accordingly, so I knew it must be possible to modify in code. Using the answer on this question: zoom css/javascript
I can get the element to zoom in and out with code:
dialog.setStyle('WebkitTransform', 'scale(0.1)')
Now I could write a 'native' function to do this, but then I'd lose out on all the great animation options in Fx. Can anyone suggest an elegent way to achieve this with Fx?
yes, you need to hack some of the CSS parsers in the mootools core to enable FX to work with them.
check this fun example I did a while back for another SO problem: http://jsfiddle.net/dimitar/ZwMUH/ - click on any 2 icons to swap them and it will transition them via scale.
or this light box base class I wrote that also uses it: http://jsfiddle.net/dimitar/6creP/
at its basic, start by modding the parsers:
Element.Styles.MozTransform = "rotate(#deg) scale(#)";
Element.Styles.MsTransform = "rotate(#deg) scale(#)";
Element.Styles.OTransform = "rotate(#deg) scale(#)";
Element.Styles.WebkitTransform = "rotate(#deg) scale(#)";
Object.append(Fx.CSS.Parsers, {
TransformScale: {
parse: function(value) {
return ((value = value.match(/^scale\((([0-9]*\.)?[0-9]+)\)$/i))) ? parseFloat(value[1]) : false;
},
compute: function(from, to, delta) {
return Fx.compute(from, to, delta);
},
serve: function(value) {
return 'scale(' + value + ')';
}
}
});
also relevant, define public and scripting vers of all styles cross browser:
transforms: {
computed: ['transformProperty', 'WebkitTransform', 'MozTransform', 'OTransform', 'msTransform'],
raw: ['transform', '-webkit-transform', '-moz-transform', '-o-transform', 'msTransform']
};
detection method which will loop through the transforms defined above and return the first one that the element supports as the definitive property to work with in the future, or opacity as fallback if unavailable:
var testEl = new Element("div"),
self = this;
this.scaleTransform = this.options.transforms.computed.some(function(el, index) {
var test = el in testEl.style;
if (test) {
self.prop = self.options.transforms.raw[index];
}
return test;
});
if (!this.prop) {
this.prop = "opacity";
}
then this.prop will refer to the correct browser property, vendor prefixed or opacity as fallback for tweening/morphing whereas this.scaleTransform will be a boolean that points to the ability to scale - you can then check against that to see if its supported when you are creating the morph object.
The object itself would be like this:
var morphObj = {};
morphObj[this.prop] = ["scale(0)", "scale(1)"]; // call it dynamically
el.morph(morphObj);
other solutions are available such as this plugin http://mootools.net/forge/p/fx_tween_css3, there's also one by Theiry Bela I know of: https://github.com/tbela99/Fx.css
its also going to be natively available in mootools 2.0
have fun.