Re: [chromium-html5] HTML5 localStorage and chrome extensions

2,299 views
Skip to first unread message

Mohamed Mansour

unread,
Jun 23, 2011, 11:41:05 PM6/23/11
to Mika, Chromium-extensions
Hi Mika,

-Chromium-HTML5 to BCC
+Chromium-Extension to CC

That will get you the localStorage key count in your extension context, not your tab context. You would need to do this in a Content Script [1] and through Message Passing [2] you can pass the result to your extensions browser action [3].

Summarizing, basically you send a request from your browser action to the tab content script asking for the pages localStorage using extension message passing. 

For example, the following snippet [4] will get the selected text from the tab to a service. You can modify that script to get the localStorage count instead and present it in a browser action instead. 

Good Luck!

Kind regards,
Mohamed Mansour

[2] - http://code.google.com/chrome/extensions/messaging.html




On Thu, Jun 23, 2011 at 9:09 PM, Mika <michael...@gmail.com> wrote:
I think I'm trying to do something basic, and I hope that someone
points out my flaws.  I have written a small chrome extension which I
will post the contents of below. My issue is that in the chrome
browser address var, if I type javascript:alert(localStorage.length)
if returns a number.  However from my extension, which calls this
javascript alert, when the script runs, it says '0' meaning nothing is
in the localStorage.

Is there a simple way to fix this in my code?  I've searched around
and found multiple reasons, none that I can pin point to be true or
able to fix.

I think my issue is  the chrome extension "privacy plugin" runs ffrom
'file:///' which is not the same origin as the localStorage in the
browser.

but how could I circumvent this or fix this.  I simply want to use
this extension to see how many keys are in the localstorage, and later
after I fix this, be able to do stuff with the data in the
localStorage.


in the manifest.json

{
 "name": "Privacy Plugin",
 "version": "1.0",
 "description": "The first extension that I made.",
 "permissions": [
   "tabs", "http://*/*", "https://*/*"
 ],
 "homepage_url": "https://http://www.truststc.org/",
 "browser_action": {
   "default_title": "Privacy Plugin",
   "default_icon": "Bob_Cool.png",
   "popup": "test.html"
 }
}

in the test.html:



<!DOCTYPE html>
<html>
<head>
   <title>Javascript Window Location Href</title>
</head>
<body>

   <script language="javascript" type="text/javascript">
   <!--
        alert(window.localStorage.length);

       function listAllItems(){
               for(i=0;i<=localStorage.length-1;i++){
               key =  window.localStorage.key(i);
               alert(key);
               val =  window.localStorage.getItem(key);
               alert(val);
               }
       }

    //-->
   </script>

</body>
</html>


Thanks in advance!

--
You received this message because you are subscribed to the Google Groups "Chromium HTML5" group.
To post to this group, send email to chromiu...@chromium.org.
To unsubscribe from this group, send email to chromium-html...@chromium.org.
For more options, visit this group at http://groups.google.com/a/chromium.org/group/chromium-html5/?hl=en.


Mohamed Mansour

unread,
Jun 24, 2011, 5:34:05 PM6/24/11
to Mika ayenson, Chromium-extensions
Hi Mika,

Looking good so far, just one comment. You have to remember that content scripts run in the context of web pages, while extension pages run in their own extension context. In the example above that you have provided you stated, I see a couple of issues:

  1. chrome.browserAction.onClicked.addListener is not needed because you have specified a popup to show in the manifest (popup": "test.html"). You can't use both. Your code should change in a way that once you click on that browser action the test.html will directly query the current tab and ask the content script for its local storage.
  2. You need to define a "tabs" permission as defined in the docs here http://code.google.com/chrome/extensions/tabs.html#manifest, because you are using extension message passing.
  3. You need to get the current tab before sending the request

       chrome.tabs.getCurrent(function(tab) {
         chrome.tabs.sendRequest(tab.id{method: "getlocalStorage"}, function(response) {
         
        });
       })

  4. When getting a response back from the content script, you are not reading the response object. The whole point of using message passing is to get a message from the web page context to the extension context. The message we are getting in this case is the localStorage length.

         listAllItems(response.data);

  5. Your listAllItems, should not call localStorage, remember we said calling localStorage from the extension context is different than calling localStorage from the web page context. Since we passed in the data through the parameter all you do is:
     
    function listAllItems(data) {
        // Do whatever you want.
        alert(data);
    }
Your content script is correct, you listen for events from the extension context and when your extension is requesting "getlocalStorage" your sending back the length of that object. I have answered something similar on StackOverflow if you would like to take a look: http://stackoverflow.com/questions/3937000/chrome-extension-accessing-localstorage-in-content-script

Kind regards,
Mohamed Mansour



On Fri, Jun 24, 2011 at 2:46 PM, Mika ayenson <michael...@gmail.com> wrote:
Thank you Mohamed for your response! I believe I carefully went through the four links and have edited my files.  However, when I click my extension, a small little white box appears, but it's not displaying the data in the local storage as expected; nor is it displaying a zero as before.  I went through the message passing, and content strips to produce the following files:  Is there something wrong with my permissions or matches that causes nothing to popup?  Thank you again!

//manifest.json

{
  "name": "Privacy Plugin",
  "version": "1.0",
  "description": "The first extension that I made.",
  "permissions": [
    "tabs", "http://*/*", "https://*/*"
  ],
  "content_stripts": [
   {
"matches": ["tabs", "http://*/*", "https://*/*"],
  "js":["mika.js"]
  }],
  "homepage_url": "https://http://www.truststc.org/",
  "browser_action": {
    "default_title": "Privacy Plugin",
    "default_icon": "Bob_Cool.png",
    "popup": "test.html"
  }  
}

//test.html

<!DOCTYPE html>
<html>
<head>
    <title>Javascript Window Location Href</title>
</head>
<body onUnload() = "alert(window.localStorage.length)">

    <script language="javascript" type="text/javascript">
    <!--

chrome.browserAction.onClicked.addListener(function(tab) {
  chrome.tabs.sendRequest(tab.id, {method: "getlocalStorage"}, function(response){
     listAllItems();
  });
});

 function listAllItems(){
               for(i=0;i<=localStorage.length-1;i++){
               key =  window.localStorage.key(i);
               alert(key);
               val =  window.localStorage.getItem(key);
               alert(val);
               }
       }
     //-->           
    </script>
</body>
</html>

//mika.js

chrome.extension.onRequest.addListener(
  function(request, sender, sendResponse) {
    console.log(sender.tab ?
                "from a content script:" + sender.tab.url :
                "from the extension");
    if (request.method == "getlocalStorage")
      sendResponse({data: localStorage.length});
    else
      sendResponse({}); // snub them.
  });


--
____________________________________________________________
Mika Ayenson
Worcester Polytechnic Undergraduate
Team for Research in Ubiquitous Secure Technology (TRUST) at UCB
A Spark Inspired to be Great



Message has been deleted

Boris Smus

unread,
Jun 28, 2011, 11:47:18 AM6/28/11
to Mika, Chromium-extensions
Mika,

Quoting the docs, "A message can contain any valid JSON object". The problem is probably that localStorage needs to be serialized before sending. So this line:

   sendResponse({data: localStorage});

Sends a Storage object (not valid JSON). Try serializing it on send, and deserializing it on receive, or implementing a message passing protocol that lets you get at specific keys in the localStorage.

- Boris



On Mon, Jun 27, 2011 at 10:21 AM, Mika <michael...@gmail.com> wrote:
Thanks Mansour!  Just a heads up. I'm not sure how to properly use
this discussion board. I posted a similar topic, and didn't see it
posted, so I thought it wasn't being posted, and I don't know how to
delete it, or where to find it.

Moving on,

Hello Everyone,
 Perhaps there is an error with the message passing? As a
user, I should be able to click the extension and receive a alert of
the current local storage. I have followed the tutorials and advice
from several forums but still no luck.

Could someone tell me where I am making the mistake?

Thank you!


//manifest.json

{
 "name": "Privacy Plugin",
 "version": "1.0",
 "description": "The first extension that I made.",
 "browser_action": {
 "default_title": "Privacy Plugin",
 "default_icon": "Bob_Cool.png"
 },
 "background page": "background.html",

 "homepage_url": "https://http://www.truststc.org/",
 "content_stripts": [
 {
     "matches": ["<all_urls>"],
     "js":["mika.js"]
 }],
 "permissions": [
 "tabs"
 ]

}



//mika.js

chrome.extension.onRequest.addListener(
 function(request, sender, sendResponse) {
 if (request.method == "getlocalStorage")
   sendResponse({data: localStorage});

 else
   sendResponse({}); // snub them.
 });


//background.html



<!DOCTYPE html>
<html>
<head>
 <title>Javascript Window Location Href</title>
</head>
<body onUnload() = "alert(window.localStorage.length)">

 <script>

<!--


chrome.tabs.getSelected(null,function(tab) {
  chrome.tabs.sendRequest(tab.id, {method: "getlocalStorage"},
listAllItems(response.data) {

 });
 });


chrome.browserAction.onClicked.addListener(function(tab) {
 chrome.tabs.sendRequest(tab.id, {method: "getlocalStorage"},
listAllItems(response.data){
 alert(response.data.length);
 });
});

 function listAllItems(data){
            for(i=0;i<=data.length-1;i++){
            key =  data.key(i);
            alert(data);
            val =  data.getItem(key);

            alert(val);
            }
    }

  //-->
 </script>

</body>
</html>


On Jun 24, 5:34 pm, Mohamed Mansour <m...@chromium.org> wrote:
> Hi Mika,
>
> Looking good so far, just one comment. You have to remember that content
> scripts run in the context of web pages, while extension pages run in their
> own extension context. In the example above that you have provided you
> stated, I see a couple of issues:
>
>    1. chrome.browserAction.onClicked.addListener is not needed because you

>    have specified a popup to show in the manifest (popup": "test.html"). You
>    can't use both. Your code should change in a way that once you click on that
>    browser action the test.html will directly query the current tab and ask the
>    content script for its local storage.
>    2. You need to define a "tabs" permission as defined in the docs here

>    http://code.google.com/chrome/extensions/tabs.html#manifest, because you
>    are using extension message passing.
>    3. You need to get the current tab before sending the request

>
>       chrome.tabs.getCurrent(function(tab) {
>         chrome.tabs.sendRequest(tab.id, {method: "getlocalStorage"},
>    function(response) {
>
>        });
>       })
>
>    4. When getting a response back from the content script, you are not

>    reading the response object. The whole point of using message passing is to
>    get a message from the web page context to the extension context. The
>    message we are getting in this case is the localStorage length.
>
>         listAllItems(response.data);
>
>    5. Your listAllItems, should not call localStorage, remember we said

>    calling localStorage from the extension context is different than calling
>    localStorage from the web page context. Since we passed in the data through
>    the parameter all you do is:
>
>    function listAllItems(data) {
>        // Do whatever you want.
>        alert(data);}
>
> Your content script is correct, you listen for events from the extension
> context and when your extension is requesting "getlocalStorage" your sending
> back the length of that object. I have answered something similar on
> StackOverflow if you would like to take a look:http://stackoverflow.com/questions/3937000/chrome-extension-accessing...
>
> Kind regards,
> Mohamed Mansour
> >>> To post to this group, send email to chromium-ht...@chromium.org.

> >>> To unsubscribe from this group, send email to

> >>> For more options, visit this group at
> >>>http://groups.google.com/a/chromium.org/group/chromium-html5/?hl=en.
>
> > --
> > ____________________________________________________________
> > Mika Ayenson
> > Worcester Polytechnic Undergraduate
> > Team for Research in Ubiquitous Secure Technology (TRUST) at UCB
> > A Spark Inspired to be Great
>
> > michael.ayen...@wpi.edu : email
> > ayen...@eecs.berkeley.edu : email
> >508-507-9072: cell

--
You received this message because you are subscribed to the Google Groups "Chromium-extensions" group.
To post to this group, send email to chromium-...@chromium.org.
To unsubscribe from this group, send email to chromium-extens...@chromium.org.
For more options, visit this group at http://groups.google.com/a/chromium.org/group/chromium-extensions/?hl=en.


.oM, .z0DeRc, a[href^="http://pagead2.googlesyndication.com/"], div.MI { display: none !important; }

Mika

unread,
Jun 28, 2011, 2:13:05 PM6/28/11
to Chromium-extensions
I'm using JSON.stringify and JSON.parse, which was a great find!
However, I think there may be two more mistakes, which i'm not sure
how to fix.

1. I call getCurrent to get the current tab, but i'm not sure i'm
properly using it. Once I call the function, am I suppose to do
anything else with the tab?

2. in my addListener, I tried to alert a basic string, however, it
didn't alert which I suspect means the function response is not being
called. Do I need two different onRequest methods in my content
script?

//mika.js
chrome.extension.onRequest.addListener(
function(request, sender, sendResponse) {
if (request.method == "getlocalStorage")
var objectString = JSON.stringify(localStorage);
sendResponse({data: objectString});
else
sendResponse({}); // snub them.

});

//background.html
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<script>

function listAllItems(data){
for(i=0;i<=data.length-1;i++){
key = data.key(i);
alert(data);
val = data.getItem(key);
alert(val);
}
};

chrome.tabs.getCurrent(function(tab) { //get the current tab, but
now that I have it, how do i use it?
chrome.tabs.sendRequest(tab.id, {method: "getlocalStorage"},
function(response){
});
});


chrome.browserAction.onClicked.addListener(function(tab) {
var myObjectRetrieved = null;
chrome.tabs.sendRequest(tab.id, {method: "getlocalStorage"},
function(response){
myObjectRetrieved = JSON.parse(response.data); //message received
alert("hello"); //not alerting so this function response must not
be getting called.
listAllItems(myObjectRetrieved);
});
});

</script>
</body>
</html>

Thank you for your time!
> ...
>
> read more »

Mohamed Mansour

unread,
Jun 29, 2011, 12:57:34 AM6/29/11
to Mika, Chromium-extensions
Hi Mika,

Remember that background page is a single long running script. It is like a singleton to your extension. You can only have one background page and it gets run immediately and lives until all your Chrome instances closes.

From a quick glance at your code above, your placing the logic of "chrome.tabs.getCurrent" by itself, that wont work in your case. You need something to get triggered like how your doing it in "chrome.browserAction.onClicked.addListener". Since your saying the alert(hello) is not being called, are you sure your browserAction is being called?

If your browser action is not being called, I would assume:
  1. There are errors in your code (check the Web Inspector to see if any errors exist in Background Page) To open up the web inspector, visit chrome://extensions and enable "Developer mode". Then click "background.html" for your extension.
  2. Your manifest has a popup defined. AFAIK You cannot mix a popup.html and the the browser action listener together. You have to use one of them, not both.
Learn how to use the Web Inspector, it will really help you solve problems, because stuff like this would show up there quickly, it is recommended for any web applications developer. 

Kind regards,
Mohamed Mansour




--

Mika

unread,
Jun 29, 2011, 12:38:52 PM6/29/11
to Chromium-extensions
Hi Mansour,

What you suggested about the onClicked listener makes more sense.
With the code before, it was firing the getCurrent(Tab) as soon as the
extension was reloaded, Now it fires upon an onClicked listener. Now
that I have two listeners in the background, logically, do I need two
listeners in the content script? Right now both click listeners in
the background.html are sending request with the same method, which
makes me think that in the content script, upon request they will both
try to access the onRequest listener. Is this a problem, or are they
executed at different times?

Also, when I get the current tab, how do I use it? Do I have to do
more with the tab once the method is called? Right now, I;m calling
the current tab, but it seems like im not doing anything with it. I
took your advice and looked at the web inspector and found an error
getting the id with the current tab and looked at the actual function
getCurrent which said: 'May be undefined if called from a non-tab
context (for example: a background page or popup view).' so I switched
the function to getSelected() and the error went away!

I'm sure the onClick listener is working in both cases now because the
alerts work when directly in the listener. Once I move the alert in
the function callback of the sendRequest method, it stops working,
which is why I believe there's an error in the message passing.

My logic right now to my understanding is,
1. onClick get the current tab
2. onClick sendRequest to get content script
3. send response of localstorage serialized
4. receive message deseralize
5. manipulate received data

between step 1 and 2, I feel like i'm missing something, but I have
not found many examples to assure me im doing this right.

Also my manifest does not include a popup.

Thank you!
Mika Ayenson

My updates are below.
//background.html
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<script>

function listAllItems(data){
for(i=0;i<=data.length-1;i++){
key = data.key(i);
alert(data);
val = data.getItem(key);
alert(val);
}
};

chrome.browserAction.onClicked.addListener(function(tab) {
alert("in tab"); // this works.

chrome.tabs.getSelected(function(tab) { //get the current tab, but
now that I have it, how do i use it?
chrome.tabs.sendRequest(tab.id, {method: "getlocalStorage"},
function(response){
});
});

});

chrome.browserAction.onClicked.addListener(function(tab) {
var myObjectRetrieved = null;
alert("in responses"); // this works.
chrome.tabs.sendRequest(tab.id, {method: "getlocalStorage"},
function(response){
myObjectRetrieved = JSON.parse(response.data); //message is
suppose to be received here
alert("hello"); //not alerting so this function response must not
be getting called.
listAllItems(myObjectRetrieved);
});
});

</script>
</body>
</html>

//mika.js

chrome.extension.onRequest.addListener(
function(request, sender, sendResponse) {
if (request.method == "getlocalStorage"){
alert("in mika.js");
var objectString = JSON.stringify(localStorage);
sendResponse({data: objectString});
}
else
sendResponse({}); // snub them.

});


//manifest.json
{
"name": "Privacy Plugin",
"version": "1.0",
"description": "The first extension that I made.",
"permissions": [
"tabs"
],
"browser_action": {
"default_title": "Privacy Plugin",
"default_icon": "Bob_Cool.png"
},
"background_page": "background.html",
"homepage_url": "https://http://www.truststc.org/",
"content_stripts": [
{
"matches": ["<all_urls>"],
"js":["mika.js"]
}
]

}

On Jun 29, 12:57 am, Mohamed Mansour <m0.interact...@gmail.com> wrote:
> Hi Mika,
>
> Remember that background page is a single long running script. It is like a
> singleton to your extension. You can only have one background page and it
> gets run immediately and lives until all your Chrome instances closes.
>
> From a quick glance at your code above, your placing the logic of
> "chrome.tabs.getCurrent"
> by itself, that wont work in your case. You need something to get triggered
> like how your doing it in "chrome.browserAction.onClicked.addListener".
> Since your saying the alert(hello) is not being called, are you sure your
> browserAction is being called?
>
> If your browser action is not being called, I would assume:
>
>    1. There are errors in your code (check the Web Inspector to see if any
>    errors exist in Background Page) To open up the web inspector, visit
>    chrome://extensions and enable "Developer mode". Then click
>    "background.html" for your extension.
>    2. Your manifest has a popup defined. AFAIK You cannot mix a popup.html
> ...
>
> read more »

Mika

unread,
Jun 29, 2011, 7:16:06 PM6/29/11
to Chromium-extensions
I realized after going through my code more that the error is in the
message passing. When I send the first request to the mika.js file,
the message is not being passed to the mika.js.

I suspect there is no communication between the background.html file
and the mika.js file. My manifest is still the same, so I do not know
why there is a broken link between the .js and .html files.
> ...
>
> read more »

Mohamed Mansour

unread,
Jun 29, 2011, 8:16:47 PM6/29/11
to Mika, Chromium-extensions
Hello, comments Inlined,

On Wed, Jun 29, 2011 at 12:38 PM, Mika <michael...@gmail.com> wrote:
What you suggested about the onClicked listener makes more sense.
With the code before, it was firing the getCurrent(Tab) as soon as the
extension was reloaded, Now it fires upon an onClicked listener.  Now
that I have two listeners in the background, logically, do I need two
listeners in the content script?

Chrome extensions uses an asynchronous based architecture for its callbacks. Listeners work the same way as any other language. In this case, we are doing "chrome.extension.onRequest.addListener", key thing here is "addListener", have 10 of those defined, you will receive the message 10 times. In your case, all you need is a single listener in the content script that listens for messages from the background page which sendsRequest. I have helped many users on StackOverflow regarding this, take a look how message passing works in:
The above links have examples and some code to help you get started. To be honest, the best resource is the documentation, http://code.google.com/chrome/extensions/ it helps you understand the entire extension framework so you can be prepared when developing extensions.
 
 Right now both click listeners in
the background.html are sending request with the same method, which
makes me think that in the content script, upon request they will both
try to access the onRequest listener.  Is this a problem, or are they
executed at different times?

Why do you need two click listeners, just use one. 

Also, when I get the current tab, how do I use it?  Do I have to do
more with the tab once the method is called? Right now, I;m calling
the current tab, but it seems like im not doing anything with it.

You cannot use chrome.tabs.getCurrent from a non-tab context, so it will not work in a background page. It is even stated in the documentation:

Quote: "Gets the tab that this script call is being made from. May be undefined if called from a non-tab context (for example: a background page or popup view)."

If you want the currently selected tab, you should be using "chrome.tabs.getSelected":


took your advice and looked at the web inspector and found an error
getting the id with the current tab and looked at the actual function
getCurrent which said: 'May be undefined if called from a non-tab
context (for example: a background page or popup view).' so I switched
the function to getSelected() and the error went away!

Exactly :)
 
I'm sure the onClick listener is working in both cases now because the
alerts work when directly in the listener.  Once I move the alert in
the function callback of the sendRequest method, it stops working,
which is why I believe there's an error in the message passing.

My logic right now to my understanding is,
1. onClick get the current tab

nit: getSelected
 
2. onClick sendRequest to get content script 
3. send response of localstorage serialized
4. receive message deseralize
5. manipulate received data

between step 1 and 2, I feel like i'm missing something, but I have
not found many examples to assure me im doing this right., 
 
Also my manifest does not include a popup.

Thank you!
Mika Ayenson


Since I am a nice guy, I have placed my snippets here, it is a fully working example, download it and load it to Chrome:
 
Enjoy!

- Mohamed Mansour


> ...
>
> read more »

Reply all
Reply to author
Forward
0 new messages