How to extract the loaded javascript files from Dev Tools extension - javascript

I'm working on a chrome extension that wants to load javascript files from the current page, modify them (prettify), then update the Dev Tools Sources panel.
As a fall-back option - I don't override the usual Sources panel - But rather put them in a custom panel. (With this option, all I'd need is a list of the network resources loaded -results in the Network panel)
Ideally I'd like to override the source's pages though, in the hopes of using the debugging tools available to the dev tools.

I don't know it's possible to replace the script on the fly.
But you can inject some code from devtools-panel into the currently inspected web page as follows:
chrome.devtools.panels.create(
'your-extension-name',
'icon.png',
'panel.html',
function (pPanel) {
pPanel.onShown.addListener(function () {
var scriptToInject = function () {
document.addEventListener('DOMContentLoaded', function () {
var script = document.getElementsByTagName('script')[0];
var parent = script.parentElement;
parent.removeChild(script);
var newScript = document.createElement('script');
newScript.textContent = 'xxx'; // Doesn't work?
parent.appendChild(newScript);
}, false);
};
// Reloads the page.
chrome.devtools.inspectedWindow.reload({
injectedScript: '(' + scriptToInject.toString() + '())'
});
});
});

Related

Improve page load latency in chrome extension

I'm building a google chrome extension that looks at a webpage, does some calculations based on features of the page, and then loads an iFrame to display the results. Currently, I am working on trying to create a more accessible version for visually-impared users. I have an option in my options page to allow users to click if they want to use the visually accessible option, and then that information is stored as a boolean in browser storage. The issue is, I have to check for that boolean in storage every single time I load the iFrame (which is every time the page switches or refreshes), and it adds roughly 500ms of latency to the iFrame load.
I have tried using both chrome.storage.sync, and localStorage (from background, with message passing to my content script) to see if the synchronous version would be a bit faster, but they both add roughly 500ms to the running of my content script. Right now I have two different html files, the standard one and the visually accessible one, and the content script chooses which to load based on retrieving the accessibility boolean from storage. If there is a faster way to just programmatically switch the css that the standard html file loads, I could do that as well. The thing is, any way I figure it, I just can't seem to think of a way to avoid having to retrieve the boolean from storage every single time the iFrame loads.
I suppose I'm wondering if there is some other way around this, like if I could somehow direct the extension to just automatically use a certain version of the html based on which option the user selects when they install the extension. Any suggestions would be greatly appreciated.
Here is the function in question (from content script):
function insertFrame(){
var extensionOrigin = 'chrome-extension://' + chrome.runtime.id;
if (!location.ancestorOrigins.contains(extensionOrigin)) {
chrome.runtime.sendMessage({contentScriptQuery: "accessible?"}, function(response){
var accessible = response;
if(accessible === "true"){
//load the accessible frame
var iframe = document.createElement('iframe');
iframe.id = "myFrame";
iframe.src = chrome.runtime.getURL('accessible.html');
document.body.appendChild(iframe);
}else{
//load the regular frame
var iframe = document.createElement('iframe');
iframe.id = "myFrame";
iframe.src = chrome.runtime.getURL('popup.html');
document.body.appendChild(iframe);
}
console.log("Time to run content script:", Date.now() - timer);
});
}
//for testing purposes
// var extensionOrigin = 'chrome-extension://' + chrome.runtime.id;
// if (!location.ancestorOrigins.contains(extensionOrigin)) {
// var iframe = document.createElement('iframe');
// iframe.id = "myFrame";
// iframe.src = chrome.runtime.getURL('popup.html');
// document.body.appendChild(iframe);
// }
// console.log("Time to run content script:", Date.now() - startTime);
}
And in my background page:
chrome.runtime.onMessage.addListener(function (request, sender, sendResponse){
if(request.contentScriptQuery === 'accessible?'){
var a = localStorage.getItem('accessible');
sendResponse(a);
}
return true; //with or without this line, timing is the same
});
I've been testing the content script just by commenting out each half (with and without reading from storage). You can see the line where I am logging how many milliseconds have elapsed since the content script started running. I have also verified this latency by testing load times in the network panel of dev tools. I get an average of 6.33s for load time without reading storage, and 6.72s with reading storage, which confirms the timing discrepancy I am logging in my content script. The only thing I am changing between tests are commenting out the half of the function so that I can test the other half.

chrome.tabs.create/executeScript > call function that belongs to the page

I'm developing an extension for Google Chrome and the problem I'm having is I need to be able to call a JavaScript function that belongs to the webpage that's opened in the tab.
For details, the website is my website, therefore I know that function does exist. That function does a lot of things based on a string value. I want the user to be able to highlight text on any webpage, click a button from the Chrome extension that automatically loads my webpage and calls that function with the highlighted text as it's value.
Here's what I got so far:
chrome.tabs.create({ url: "https://mywebsite.com" }, function (tab) {
var c = "initPlayer('" + request.text + "');"; ////'request.text' is the highlighted text which works
chrome.tabs.executeScript(tab.id, { code: c });
});
But Chrome console says: "Uncaught ReferenceError: initPlayer is not defined."
I know that function does exist as it is in my code on my own website.
Any help is highly appreciated. Thanks!
This happens because pages and content scripts run inside two separate javascript contexts. This means that content scripts cannot acces functions and variables inside a page directly: you'll need to inject a script into the page itself to make it work.
Here is a simple solution:
chrome.tabs.create({url: "https://mywebsite.com"}, function (tab) {
var c = "var s = document.createElement('script');\
s.textContent = \"initPlayer('" + request.text + "');\";\
document.head.appendChild(s);"
chrome.tabs.executeScript(tab.id, {code: c});
});
NOTE: since January 2021, use Manifest V3 with chrome.scripting.executeScript() instead of chrome.tabs.executeScript().
With the above code you will basically:
Create the tab
Inject the code (variable c) into it as a content script that will:
Create a script with the code you want to execute on the page
Inject the script in the page and, therefore, run its code in the page context

ReportViewer Web Form causes page to hang

I was asked to take a look at what should be a simple problem with one of our web pages for a small dashboard web app. This app just shows some basic state info for underlying backend apps which I work heavily on. The issues is as follows:
On a page where a user can input parameters and request to view a report with the given user input, a button invokes a JS function which opens a new page in the browser to show the rendered report. The code looks like this:
$('#btnShowReport').click(function () {
document.getElementById("Error").innerHTML = "";
var exists = CheckSession();
if (exists) {
window.open('<%=Url.Content("~/Reports/Launch.aspx?Report=Short&Area=1") %>');
}
});
The page that is then opened has the following code which is called from Page_Load:
rptViewer.ProcessingMode = ProcessingMode.Remote
rptViewer.AsyncRendering = True
rptViewer.ServerReport.Timeout = CInt(WebConfigurationManager.AppSettings("ReportTimeout")) * 60000
rptViewer.ServerReport.ReportServerUrl = New Uri(My.Settings.ReportURL)
rptViewer.ServerReport.ReportPath = "/" & My.Settings.ReportPath & "/" & Request("Report")
'Set the report to use the credentials from web.config
rptViewer.ServerReport.ReportServerCredentials = New SQLReportCredentials(My.Settings.ReportServerUser, My.Settings.ReportServerPassword, My.Settings.ReportServerDomain)
Dim myCredentials As New Microsoft.Reporting.WebForms.DataSourceCredentials
myCredentials.Name = My.Settings.ReportDataSource
myCredentials.UserId = My.Settings.DatabaseUser
myCredentials.Password = My.Settings.DatabasePassword
rptViewer.ServerReport.SetDataSourceCredentials(New Microsoft.Reporting.WebForms.DataSourceCredentials(0) {myCredentials})
rptViewer.ServerReport.SetParameters(parameters)
rptViewer.ServerReport.Refresh()
I have omitted some code which builds up the parameters for the report, but I doubt any of that is relevant.
The problem is that, when the user clicks the show report button, and this new page opens up, depending on the types of parameters they use the report could take quite some time to render, and in the mean time, the original page becomes completely unresponsive. The moment the report page actually renders, the main page begins functioning again. Where should I start (google keywords, ReportViewer properties, etc) if I want to fix this behavior such that the other page can load asynchronously without affecting the main page?
Edit -
I tried doing the follow, which was in a linked answer in a comment here:
$.ajax({
context: document.body,
async: true, //NOTE THIS
success: function () {
window.open(Address);
}
});
this replaced the window.open call. This seems to work, but when I check out the documentation, trying to understand what this is doing I found this:
The .context property was deprecated in jQuery 1.10 and is only maintained to the extent needed for supporting .live() in the jQuery Migrate plugin. It may be removed without notice in a future version.
I removed the context property entirely and it didnt seem to affect the code at all... Is it ok to use this ajax call in this way to open up the other window, or is there a better approach?
Using a timeout should open the window without blocking your main page
$('#btnShowReport').click(function () {
document.getElementById("Error").innerHTML = "";
var exists = CheckSession();
if (exists) {
setTimeout(function() {
window.open('<%=Url.Content("~/Reports/Launch.aspx?Report=Short&Area=1") %>');
}, 0);
}
});
This is a long shot, but have you tried opening the window with a blank URL first, and subsequently changing the location?
$("#btnShowReport").click(function(){
If (CheckSession()) {
var pop = window.open ('', 'showReport');
pop = window.open ('<%=Url.Content("~/Reports/Launch.aspx?Report=Short&Area=1") %>', 'showReport');
}
})
use
`$('#btnShowReport').click(function () {
document.getElementById("Error").innerHTML = "";
var exists = CheckSession();
if (exists) {
window.location.href='<%=Url.Content("~/Reports/Launch.aspx?Report=Short&Area=1") %>';
}
});`
it will work.

Reload updated java<script> code without fully reloading the html page

I am developing a single page web application, that has many different features and forms. When developing a deep (I mean something that is not on the home page) feature, I go through this cycle:
develop the code, editing classes and functions
refresh the whole page
clicking all the way till I get to the part that I need to test (that adds up to about a minute sometimes)
testing the new code
back to the (1) code editor doing updates
doing about 15 minor edits, can take a frustrating 30 minutes of repeated reloading and clicking
Is there any plugin, piece of javascript, or method, that allows to reload the updated javascript without reloading everything, so one can skip the 2. and 3. from the cycle above and continue doing live tests?
If there's no such thing, I am planning on developing a little javascript plugin that will reload the scripts, and probably with socket.io connection to a backend node.js server that will watch the files for any updates and push the load events to the browser.
So, I am interested in any idea about this, any thing that I should take into consideration when writing the plugin.
Thanks : )
You could do something like this.
function LoadMyJs(scriptName) {
var docHeadObj = document.getElementsByTagName("head")[0];
var dynamicScript = document.createElement("script");
dynamicScript.type = "text/javascript";
dynamicScript.src = scriptName;
docHeadObj.appendChild(newScript);
}
Call the LoadMyJs function on page load
<body onLoad="LoadMyJs()">
Then reload with the click of a button (or from your console)
<input type="button" name="reloadjs" value="Reload JavaScript" onclick="LoadMyJs('my_live_loading_script.js')">
This could be simplified using e.g jQuery
Thanks to:
http://www.philnicholas.com/2009/05/11/reloading-your-javascript-without-reloading-your-page/
Here's what I came up with: a Node.js module that watches for changes in .js & .coffee scripts, and pushes the changes to the browser upon editing the files.
It works standalone, even if you are developing on filesystem file:/// without using a web server.
It works with any framework, just launch the standalone script and point it to your js/ directory.
It has an express.js helper, that make it run using the same server instance.
It is as easy as
adding a single line of <script> tag to your existing code, and
running the live script, pointing it to the html root.
code: 🐱/etabits/live.js
That's may be not the best answer but for local developments I use that firefox plugins:
https://addons.mozilla.org/en-US/firefox/addon/auto-reload/
This reload the css, js or anything present in a directory
For dev which really needs to be remotely , I use that small js code you can adapt for reloading js.
function refreshCss(rule){
if (rule == null)
rule = /.*/;
var links = document.getElementsByTagName("link");
for(var i=0;i<links.length;i++)
{
if (!links[i].href.match(rule))
continue;
if (! links[i].href.match(/(.*)time=/)){
if (links[i].href.match(/\?/))
var glue = '&';
else
var glue = '?';
links[i].href += glue+"time="+new Date().getTime();
}
else{
links[i].href.replace(/time=\d+/, "time"+new Date().getTime());
}
}
if (!no_refresh)
{
setTimeout(function(){refreshCss(rule)}, 5000);
}
};
// and then call it refreshCss("regex to match your css, or not"); var no_refresh=false;
Edit: this is a version with "setTimeout", but you can easily made a "keypress" version of it
Replace with dynamic script.
function LoadMyJs(scriptName)
{
var docHeadObj = document.getElementsByTagName("head")[0];
var dynamicScript = document.createElement("script");
dynamicScript.type = "text/javascript";
dynamicScript.src = scriptName;
docHeadObj.appendChild(dynamicScript);
}

Load JavaScript dynamically [duplicate]

This question already has answers here:
JQuery to load Javascript file dynamically
(2 answers)
Closed 7 years ago.
I have a web page and a canvas with Google Maps embedded in it. I am using jQuery on this site.
I want to load Google Maps API only if the user clicks on "Show me the map". Further, I want to take away the whole loading of the Google Maps from the header in order to improve my page performance.
So I need to load JavaScript dynamically. What JavaScript function I can use?
You may want to use jQuery.getScript which will help you load the Google Maps API javascript file when needed.
Example:
$.getScript('http://maps.googleapis.com/maps/api/js?libraries=geometry&sensor=true', function(data, textStatus){
console.log(textStatus, data);
// do whatever you want
});
Use the Loading on Demand Loading Strategy
Loading on Demand
The previous pattern loaded additional JavaScript unconditionally after page load, assuming
that the code will likely be needed. But can we do better and load only parts of
the code and only the parts that are really needed?
Imagine you have a sidebar on the page with different tabs. Clicking on a tab makes an
XHR request to get content, updates the tab content, and animates the update fading
the color.
And what if this is the only place on the page you need your XHR and animation
libraries, and what if the user never clicks on a tab?
Enter the load-on-demand pattern. You can create a require() function or method that
takes a filename of a script to be loaded and a callback function to be executed when
the additional script is loaded.
The require() function can be used like so:
require("extra.js", function () {
functionDefinedInExtraJS();
});
Let’s see how you can implement such a function. Requesting the additional script is
straightforward. You just follow the dynamic element pattern. Figuring out
when the script is loaded is a little trickier due to the browser differences:
function require(file, callback) {
var script = document.getElementsByTagName('script')[0],
newjs = document.createElement('script');
// IE
newjs.onreadystatechange = function () {
if (newjs.readyState === 'loaded' || newjs.readyState === 'complete') {
newjs.onreadystatechange = null;
callback();
}
};
// others
newjs.onload = function () {
callback();
};
newjs.src = file;
script.parentNode.insertBefore(newjs, script);
}
“JavaScript Patterns, by Stoyan Stefanov
(O’Reilly). Copyright 2010 Yahoo!, Inc., 9780596806750.”
you would just generate the script tag via javascript and add it to the doc.
function AddScriptTag(src) {
var node = document.getElementsByTagName("head")[0] || document.body;
if(node){
var script = document.createElement("script");
script.type="text/javascript";
script.src=src
node.appendChild(script);
} else {
document.write("<script src='"+src+"' type='text/javascript'></script>");
}
}
I think you're loking for this http://unixpapa.com/js/dyna.html
<input type="button" onclick="helper()" value="Helper">
<script language="JavaScript">
function helper()
{
var head= document.getElementsByTagName('head')[0];
var script= document.createElement('script');
script.type= 'text/javascript';
script.src= 'your_script_url';
head.appendChild(script);
}
</script>
I used the Tangim response, but after found that is more easy use jquery html() function. When we make ajax request to html file that have html+javascript we do the follow:
$.ajax({
url:'file.html',
success:function(data){
$("#id_div").html(data); //Here automatically load script if html contain
}
});

Categories

Resources