I'm trying to modify img src attribute by getting the url from different page. Thing is i need to find it by inspecting DOM as it's not static data; i will be looking via classes and IDs.
My knowledge of chrome extensions is very limited at the time. Basicly i just started.
Look at the "PSEUDO CODE" part of background.js
manifest.json
{
"manifest_version" : 2 ,
"name": "#####" ,
"version": "1.0" ,
"description": "#####" ,
"browser_action":
{
"name": "#####" ,
"icons": ["icon.png"] ,
"default_icon": "icon.png"
},
"content_scripts": [
{
"js": [ "jquery.min.js", "background.js" ] ,
"matches": [ "http://*.#####.com/encounters/promospp.phtml"] ,
"run_at": "document_end"
}]
}
background.js
var l = document.getElementsByTagName("div");
for (var i = 0; i < l.length; i++)
{
var obj = l[i].parentNode;
if (l[i].getAttribute("class") && l[i].getAttribute("class") == "user_contact")
{
var div = l[i];
var id = div.getAttribute("id").replace("u_", "0");
var profileUrl = "../" + id + "/";
var imgs = div.getElementsByClassName("userpic");
log("found img.userpic : " + imgs.length);
if (imgs && imgs.length > 0)
{
var img = imgs[0];
var alink = document.createElement('a');
img.parentNode.appendChild(alink);
alink.setAttribute("href", profileUrl);
alink.appendChild(img);
// PSEUDO CODE - the unknown
//
// download profileUrl page html
// search for given div element
// pull src attribute value from it
// apply it to img here
}
}
}
So in essence. How to download different page and work with it
Since you are including it already and tagged your question with it, I am going to answer with jQuery, I hope you don't mind. So first I rewrite what code you have in jQuery:
$('div.user_contact').each(function(){
var id = $(this)[0].id.replace('_u','0');
var profileUrl = "../" + id + "/";
var imgs = $(this).find('.userPic');
if(imgs.length > 0){
var alink = $(document.createElement('a'));
$(this).append(alink);
$(alink).attr('href',profileUrl);
$(alink).append(imgs[0]);
//Here is where you get the page and search for the div you want
$.get(profileUrl,function(data){
//Since I don't know the layout of what you are looking for
//I will just put in some placeholder
$(imgs).first().attr('src',$('img.youWant',data).first().attr('src'));
});
// Since $.get is asynchronous, doing it like this might cause problems
// if there is more than one div.user_contact.
// In the case where there are a low number of them and you are fine running
// blocking synchronous code, then you can do it with this instead:
// $.ajax(profileUrl,{async:false,success:function(data){
}
});
You'll also need to include permissions in your manifest for the site you are $.geting from. Something like this:
"permissions":["*://*.badoo.com/*"]
Using BeardFist solution + few fixes final code looks like this:
$('div.user_contact').each(function()
{
var id = $(this)[0].id.replace('u_','0');
log(id);
var profileUrl = "../" + id + "/";
log(profileUrl);
var imgs = $(this).find('.userpic');
if(imgs.length > 0)
{
var alink = $(document.createElement('a'));
$(imgs[0]).parent().append(alink);
$(alink).attr('href',profileUrl);
$(alink).append(imgs[0]);
$.get(profileUrl, function(data)
{
$(imgs[0]).attr('src',$('img.pf_phts_b_pht', data).attr('src'));
});
}
});
It works excelent. Entire html is inside data and it even stays loged and stuff :)
Related
I am trying to bypass the error:
Cross origin requests are only supported for protocol schemes: http,
data, chrome, chrome-extension, https.
By including external javascript file containing html data. So what I want to achieve is, to load the html content when a side menu is clicked. In the process, I want the earlier data to be replaced by the new one so that I can replace the old content with the new one.
Below is the main part of the code.
function change_current_doc(clicked_file, doc_src) {
//Change current JavasScript file containing data with the new one.
var prev_doc_src = doc_src;
var prev_doc = doc;
doc_src = html_file.doc_path + '/' + clicked_file.split('.')[0] + '.json';
var scripts = document.getElementsByTagName('script');
for (var i = 0; i < scripts.length; i++) {
if (scripts[i].src.indexOf(prev_doc_src) > 0) {
scripts[i].remove();
var doc_script = document.createElement('script');
doc_script.setAttribute('src', doc_src);
document.head.appendChild(doc_script);
break;
}
}
}
$(document).ready(function () {
$('#st_side_menu').jstree({
"plugins": [
"types",
"unique",
"wholerow",
"changed"
],
"types": {
"default": {
"icon": "images/book.png",
"select_node" : function(e) {
this.toggle_node(e);
return false;
}
},
"moveType": {
"icon": "glyphicon glyphicon-transfer"
}
}
}).on('changed.jstree', function (NODE, REF_NODE) {
//Loads the new file on button click however, it is out of sync, it
//requires to be clicked two times.
var clicked_file = REF_NODE.node.a_attr.href;
if (clicked_file.length < 5){
return
}
console.log(clicked_file);
// Actual changing happens here.
change_current_doc(clicked_file, doc_src);
// data is set here.
$('#doc_container').html(doc[0]);
})
});
My json data in js file.
var doc = ["<!DOCTYPE HTML>\n<html>\n<head>\n <meta content=\"text/html;...];
What I am looking for is, if there is any way to reset the old doc global variable and set the new one without clicking twice.
I didn't need to go through all this long way if I had an option to access the web application from server. I have no option to get away with this as users will access it from a folder.
I found a solution to the problem. What I did was the following.
On the server side, I updated all JavaScript files containing html with a variable name that corresponds to the file name. Then I used a dynamic variable by accessing it through window['document_name']
eg.
var name_of_the_file = ["<!DOCTYPE HTML>\n<html>\n<head>\n <meta content=\"text/html;...];
I created another JavaScript file that contains an array of all files to be included.
eg.
var js_doc_files = ['path/to/name_of_the_file.js', ...];
In the index.html file, I did the following.
function insert_js_docs() {
// Loops through all files and add them in the index.html as a JavaScript
file in the head section of the document.
for (var j = 0; j < js_doc_files.length; j++) {
var doc_script = document.createElement('script');
doc_script.setAttribute('src', js_doc_files[j]);
document.head.appendChild(doc_script);
}
}
// executes the insert here.
insert_js_docs();
$(document).ready(function () {
$('#st_side_menu').jstree({
"plugins": [
"types",
"unique",
"wholerow",
"changed",
"conditionalselect"
],
"types": {
"default": {
"icon": "images/book.png",
"select_node" : function(e) {
this.toggle_node(e);
return false;
}
},
"moveType": {
"icon": "glyphicon glyphicon-transfer"
}
}
}).on('changed.jstree', function (NODE, REF_NODE) {
var clicked_file = REF_NODE.node.a_attr.href;
if (clicked_file.length < 5){
return
}
// get the document name without extension and set it to
// the window object to get the clicked item html data.
var doc_name = clicked_file.split('.')[0].replace(/-/g, '_');
// Set it to the content container div
$('#doc_container').html(window[doc_name]);
})
});
Now it works on single click. Moreover, performance wise it is good. The pages' RAM usage starts around 25MB and reaches a maximum of 75MB, which is good enough.
I have made a little Chrome extension that injects some code in the current page.
This extension has a weird behaviour though, whenever the code is injected, none of the page's Javascript triggers seem to work anymore.
Would one of you have any idea what that happens? On top of fixing the code I'd really like to know why this happens.
Example : on this page : http://www.acti.fr/success-story/ghd/ if the extension injects the picture, I cannot click on either the menu or "continuer la lecture" at the bottom.
Here are the manifest and the actual code :
manifest.json
{
"manifest_version": 2,
"name": "wpi",
"description": "just an other extension",
"version": "1.0",
"content_scripts": [{
"matches": ["http://*/*", "https://*/*"],
"js": ["my-style.js"]
}]
}
my-script.js :
function wpkm_check_content(wpkm_text) {
var wpkm_word = wpkm_text.split(" ");
var wpkm_c = wpkm_word[0].localeCompare("Wordpress");
if (wpkm_c == 1)
return (1);
return (0);
}
var wpkm_html = '<div id="wpkm-bloc" style="position:absolute;right:10px;top:10px;z-index:99999">';
wpkm_html += '<img id="wpkm-img" src="https://nathanarnold.files.wordpress.com/2009/02/ssim51.gif">';
wpkm_html += '</div>';
var wpkm_sdomain = document.domain;
var wpkm_request = new XMLHttpRequest();
wpkm_request.open('GET', '/license.txt', true);
wpkm_request.onreadystatechange = function(){
if (wpkm_request.readyState === 4){
if (wpkm_request.status === 200
&& wpkm_check_content(wpkm_request.responseText) == 1) {
document.body.innerHTML += wpkm_html;
}
else {
console.log("Oh no, it does not exist!");
}
}
};
wpkm_request.send();
Any hints will be appreciated :D
You're effectively reassigning the entire innerHTML of the document body by using += append operator which causes reevaluation and recreation of the entire page and of course all previously attached event handlers aren't reattached automatically.
Use insertAdjacentHTML instead:
document.body.insertAdjacentHTML("beforeend", wpkm_html);
My simple Chrome extension is injecting a DIV at the top of document.body, then you can drag text from your page into the extension. The problem is that I want the extension DIV not to be located at top, but instead be something like a side bar to the left.
In other words I need to know how to programatically rearrange already loaded DOM structure so that all content is moved to the right and horizontally compressed and then the left area is accessible to further manipulations.
One option I was considering was to do this:
tmp = document.body.innerHTML
document.body.innerHTML = '<table><tr><td id=sidebar></td><td>'
+ tmp + '</td></tr></table>'
But this will be inneficient, will cause rerender and may have other undesired side effects.
By the way current version of the extension will inject every page "on load", but this is just a temporary solution, the side bar must be displayed when the extension button is clicked. This is not part of this question, I know how to do that. Just to let you know that the sidebar creation could be done at any time when user chooses to click the button. That's why using innerHTML is not a good option.
pageload.js
function allowDrop(ev) {ev.preventDefault()}
function drop(ev) {
ev.preventDefault();
var t = 'text', T = Array.prototype.slice.apply(ev.dataTransfer.types)
if (T.indexOf('text/html') >= 0)
t = "text/html"
console.log('text type:', t)
d1.innerHTML += '<div style="display:inline;border:2px solid #000000;">'+ev.dataTransfer.getData(t)+'</div> '
}
function createDragbar(id) {
var n = document.createElement('div')
// n.style.position = "absolute";
n.setAttribute('id', id)
n.style.border = '1px solid #aaaaaa'
n.style.height = 532
n.style.background = "teal"
n.innerHTML = "Drop your text here "
n.ondrop = drop
n.ondragover = allowDrop
document.body.insertBefore(n, document.body.firstChild)
}
createDragbar('d1')
manifest.json
{
"name": "Yakov's Demo Extension",
"description": "Just a demo",
"version": "0.1",
"permissions": [
"activeTab"
],
"content_scripts": [{
"matches": ["http://*/*", "https://*/*", "file://*/*"],
"js": ["pageload.js"]
}],
"manifest_version": 2
}
What about element.insertAdjacentHTML(position, text)?
https://developer.mozilla.org/en-US/docs/Web/API/Element.insertAdjacentHTML
My chrome extension which looks for a phone number on a webpage is not working. Essentially, i expect an icon to appear besides the number. It works on other websites, but not on say google.com search results page. E.g.: https://www.google.com/#q=macy's%20redmond Do you know why?
Here is my code.
reverphonescript.js:
var hostname = document.location.hostname;
if (hostname.indexOf('xp')== -1)
{
// Initiate recursion
wpReversePhoneLookup(document.body);
function wpReversePhoneLookup(elem) { // elem must be an element node
var nodes = elem.childNodes
, i = nodes.length
, regexp = /([\(]|)\d*([\+)]|)\d*[-\.\(\ ][0-9][0-9][0-9][-\s\.\)]*(([0-9][0-9][0-9][-\s\.][0-9][0-9][0-9][0-9])|([ ][1-9][0-9][0-9][0-9][0-9][0-9][0-9])|[1-9][0-9][0-9][0-9][0-9][0-9][0-9])]*/gi
, node, phoneNode, a, result;
while (node = nodes[--i]) {
if (node.nodeType === 1) {
// Skip anchor tags, nested anchors make no sense
//if (node.nodeName.toUpperCase() !== 'A')
wpReversePhoneLookup(node);
} else if (node.nodeType === 3) {
// Please note that the regexp has NO global flag,
// and that `node.textContent` shrinks when an address is found
while (result = regexp.exec(node.textContent)) {
//console.log(result);
node = node.splitText(result.index);
node = node.splitText(result[0].length);
phoneNode = node.previousSibling
//console.log(phoneNode)
var link = "https://pro.lookup.whitepages.com/phones?number=" + result[0];
var imgURL = chrome.extension.getURL("images/rsz_wp_16.png");
var img = new Image();
img.src = imgURL;
img.className = "wpChromeExtensionImg";
img.onclick = function() {
window.open( link ,"_blank" ,"width=1000, height=650");
};
document.getElementsByClassName("wpChromeExtensionImg").src = imgURL;
//Create link
wpLink = document.createElement('a');
wpLink.href = '#';
//Append phoneNode
wpLink.appendChild(img)
var refNode = phoneNode;
refNode.parentNode.insertBefore(wpLink, refNode.nextSibling);
}
}
}
}
}
And manifest.json:
{ // Required
"manifest_version": 2,
"name": "XP",
"version": "1.0",
"description": "XP Reverse Phone Lookup. ",
"icons": { "128": "images/rsz_xp_128.png"
},
"web_accessible_resources": [
"images/*.png",
"js/reversePhoneScript.js"
],
"browser_action": {
"default_icon": {
"19": "images/rsz_wp_19.png"
},
"default_title": "XP Reverse Phone Lookup"
},
"permissions": [
"tabs", "http://*/*", "https://*/*"
],
"content_scripts" : [
{
"matches" : ["http://*/*", "https://*/*"],
"js" : ["js/reversePhoneScript.js"],
"run_at" : "document_idle", //document_end
"all_frames" : false
}
]
}
Any help will be much appreciated.
Thanks,
Kushal.
use the chrome "inspect" tool to find your icon in the page. use the ctrl-f to find your icon in the page. https://developer.chrome.com/devtools/index
some css might be moving your icon to the far left of the screen, or much simply, no z-index tag is applied to your icon so it might be hiding behind something else. http://www.w3schools.com/CSSref/pr_pos_z-index.asp
For instance, if I input:
http://www.google.com/
It would return:
http://www.google.com/images/logos/ps_logo2.png
Using javascript/jquery. These sites would all be external. Thank you!
Since that is a Google Chrome extension, you are not bound to same origin policy.
Basically, you would need content scripts to fetch all the images within a page, and check each image's size within the DOM to know if its larger the last fetched image.
You can use Message Passing, to communicate from the Content Script to the popup/background page.
For example, I will show you how to get the largest image from a page and show it within the popup. We use all the techniques shown above and you will see the largest image within the popup if you activate it. (should show I believe :))
manifest.json (snippet)
...
"permissions": [
"tabs",
"http://*/*"
],
"content_scripts": [
{
"matches": ["http://*/*"],
"js": ["images.js"],
"run_at": "document_start",
"all_frames": true
}
]
...
popup.html
<!DOCTYPE html>
<html>
<head>
<script>
function getImage() {
chrome.tabs.getSelected(null, function(tab) {
chrome.tabs.sendRequest(tab.id, {method: "getImage"}, function (response) {
var text = document.getElementById('image');
var image = response.data;
text.src = image ? response.data : 'no_image.gif';
});
});
}
</script>
</head>
<body>
<button onclick="getImage(); ">Get Largest Image</button>
<img src="no_image.gif" id="image"/>
</body>
</html>
images.js (content script)
function getMaxImage() {
var maxDimension = 0;
var maxImage = null;
// Iterate through all the images.
var imgElements = document.getElementsByTagName('img');
for (var index in imgElements) {
var img = imgElements[index];
var currDimension = img.width * img.height;
if (currDimension > maxDimension){
maxDimension = currDimension
maxImage = img;
}
}
// Check if an image has been found.
if (maxImage)
return maxImage.src;
else
return null;
}
// Listen for extension requests.
chrome.extension.onRequest.addListener(function(request, sender, sendResponse) {
if (request.method == "getImage") {
sendResponse({data: getMaxImage()});
} else {
sendResponse({}); // snub them.
}
});
This is more web-scraping than JavaScript/jQuery.
However, given an assumption that you've received the HTML, and that it is available somehow in a JavaScript string, then something like the following might suffice for finding the maximum dimension image:
var sHTML = getHTMLSomehow(sURL);
var nMaxDim = 0;
var $pageDOM = $(sHTML);
var $objMaxDimImage;
$pageDOM.("img").each(function(){
var $this = $(this);
var nDim = parseFloat($this.width()) * parseFloat($(this).height());
if (nDim > nMaxDim){
$objMaxDimImage = $this;
nMaxDim = nDim
}
});
alert("Max dim is:" nMaxDim);
alert("Image Source:" $objMaxDimImage.attr("src"));
due to the same origin policy you cant access an external site with javascript. maybe you can write a server-side script that downloads the page (for example using wget), search for img-tags in the html code and load all found images to check the size.