I've been trying to create a Pin It button (extension of Pinterest) like chrome extension.
What i tried is firing a script when extension is clicked which can iterate through all available images on a webpage, store it in localStorage. Now i need to call an iframe (different domain ofcourse) and access these images. Since one can access localstorage only from same domain, i'm quite confused how Pinterest manages to store all images from a web page (temporarily and not on their server) and then use it in an iframe.
I also saw the code of PinIt Button extension but i can't understand a thing from it as it is too much obfuscated/encrypted or whatever.
I've read about chrome.storage
api and i haven't been able to understand it quite well. I'm not even sure if this is the thing i need to do in this case. (This is the first time i'm developing a chrome extension). Can anybody please throw some light on this and guide me the best possible way to achieve this functionality?
P.S. I've completed this extension without using <iframe>
however i need to do it with <iframe>
.
EDIT 1: I can't write complete code here but here is the flow/structure/my attempts
I start with background.js
chrome.browserAction.onClicked.addListener(function (tab) { /*This fxn fires when extension is clicked*/
chrome.tabs.executeScript(tab.id, {
"file": "bookmarklet.js"/*Calls this file*/
})
});
In bookmarklet.js
:
jQuery('body').append('<iframe class="vw_parent" id="image-grabber-container" src="" style="height: 100% !important; width: 100% !important; position: fixed !important; margin: 0% auto !important; background: rgba(17, 17, 17, 0.9) !important; left: 0 !important; right: 0 !important; z-index: 999999999 !important; top: 0% !important;"></iframe>');
jQuery('img').each(function() {
//do some checks to determine what images need to be stored
var allImgs = jQuery(this);
localStorage.setItem('myLocalImgs', allImgs);
})
vwgrid = "https://mydomain/FileToBeInjectedInIframe.php";
jQuery('#image-grabber-container').attr('src', vwgrid);
Now in FileToBeInjectedInIframe.php
var abcde = localStorage.getItem('myLocalImgs');
console.log(abcde);
//This gives NULL value
EDIT 2: As per comments and answer by DelightedD0D, i want to explain How this extension works/should work
1. User is on any webpage and then clicks the extension
2. All the images available on that webpage are displayed in an iFrame
3. User can select multiple images from this iFrame and then post them to my website
4. Reason for iFrame: If user clicks on POST IMAGE button available in iFrame and he is not logged into our website for posting the image, he should see a login popup in the same iFrame
5. If not iFrame, how would i check if the user is logged in my website as i won't be able to read session/cookie of a different domain on a different domain.
For same reasons i believe (i'm not sure though), pinterest also display images in an iFrame
TL;DR, link to an example extension at the bottom ;)
Ok, your question is a bit broad but I'll try to explain the approach I would take if I wanted to do this.
First, I'd drop the iFrame. I can't see any reason to use one here and I just dont like them personally.
I would:
- have a content script that is injected into all pages (or specific one if needed, whatever)
- the script would have a javascript class that adds a
chrome.runtime.onMessage.addListener
to the page
- this class would listen for messages from the extension
- messages would be sent to this class to trigger functions and send back a response
- for example a message like
{pageAction:"getImages"}
would trigger the getImages
function in the injected class
getImages
would get all the images and send them back to the extension
One note here, I prefer to work with images encoded as base64 strings with stuff like this rather than image urls from a whole bunch of different domains and all the CORRs, link protection,....etc. For that reason, I would have the getImages
make an ajax call to encodeImagesToBase64.php
a server passing an array of image urls. encodeImagesToBase64.php
would return an array of base64 images which are then sent to the extension.
- Now that the extension has an array of base64 images, Id save them to
chrome.storage.local
in the extension's storage area.
- Now you can show them in the popup, show them in a new tab for editing, or whatever
- If you want to show them on the page in an overlay, just make a function to do that in the javascript listener class we made and send a message to it with the images to display
To get you started, here is a javascript listener class I use to do similar things in my extensions.
(note that this relies on John Resig's Simple JavaScript Inheritance which I highly recommend using when writing Classes )
// IMPORTANT NOTE you must reload your extension via chrome://extensions
// AND reload the browser tab in order for changes to this file to be seen!!
var PageActionListener = Class.extend({
/**
* This class is meant to be injected into a webpage
* once there, it listens for messages from an extension
* messages must pass like {pageAction:"someAction", ... }
* where someAction should map to a function in this class
* responses should take the form
* {success:true, pageAction:"someAction", data:"someData", ... }
*/
attachListener: function() {
/**
* Attaches a chrome message listener to the current page
* this allows the extension to call
* the functions in this class from the context of the page
* and receive responses from those functions via messaging
*/
var _this=this;
// Listen for messages from the popup
chrome.runtime.onMessage.addListener(function (msg, sender, extensionCallback) {
// First, validate the message links to a function
if (msg.pageAction) {
// then make sure its a legit function in this class
if(typeof _this[msg.pageAction] === "function"){
// call that fucntion
_this[msg.pageAction](msg,function(response){
extensionCallback(response);
});
}
else extensionCallback({success:false,msg:msg,error:"Action not found"});
return true;
}
});
},
getImages:function(msg,callback){
/**
* Traverses the DOM looking for images and returning them
* as an array of base64 strings
* @param object msg The message that triggered this action
* @param function callback A function to be called when the action below is complete
* passes to callback the images gathered from the page
*/
var images = [];
var $images= $('img');
$images.each(function(){
var url = this.src;
images.push(url);
});
// convert images to base64
$.ajax({
type: "POST",
url: "https://somedomain.com/shared-resources/php/encodeImagesToBase64.php", // you'll need to update this to your path
data: {urls:images},
success: function(response) {
response.msg=msg;
send the response back to the extension
callback(response);
},
error: function(xhr, status, error) {
callback({success:false,msg:msg,error:error.Message})
}
});
},
// add other functions that need to be called by the extension here
});
And here is the contents of encodeImagesToBase64.php
to convert the images to base64:
<?php
if (isset($_POST['urls']) ){
$imageStrings=[];
foreach($_POST['urls'] as $url){
$imageStrings[]=base64_encode(file_get_contents($url));
}
echo json_encode(['success'=>true,'images'=>$imageStrings]);
}else{
echo json_encode(['success'=>false,'error'=>'Error: No images to encode']);;
}
Here is an example extension that kindof does what you want.
It'll need a ways to go to meet your actual needs but, it should be enough for you to understand the concepts and the approach Ive proposed above.
NOTE the example extension uses a copy of encodeImagesToBase64.php
that is hosted on my server, you'll need to host your own and update the ajax call with the path to it. Ill leave mine up for now so you can test it out, but dont count on it being around forever :)