开发者

Modify the Google 'Add Bookmark' bookmarklet to store bookmark without popup?

The bookmarklet has the following code:

javascript:(function(){var%20a=window,b=document,c=encodeURIComponent,d=a.open("http://www.google.com/bookmarks/mark?op=edit&output=popup&bkmk="+开发者_运维问答c(b.location)+"&title="+c(b.title),"bkmk_popup","left="+((a.screenX||a.screenLeft)+10)+",top="+((a.screenY||a.screenTop)+10)+",height=420px,width=550px,resizable=1,alwaysRaised=1");a.setTimeout(function(){d.focus()},300)})();

There is a validation function and a random key in the popup window:

<input type=submit name=btnA style="font-weight:bold" onclick="return _validate_add_bkmk(document.add_bkmk_form) && addp('btnA')"value="Add bookmark">

Here is the addp function:

<script>function addp(p) {document.add_bkmk_form.action = document.add_bkmk_form.action + "&" + p;return true;}</script>

The form in the popup window contains a random value called 'sig' which is part of the popup form submit action:

<form name="add_bkmk_form" action="/bookmarks/mark?sig=2bbEz24YrH7rmG2yhwYeLQ&hl=en" method=post target="_self">

Is it possible to change the bookmarklet so it autosubmits the form to create the bookmarklet? - would be great to click the bookmarklet so the current page is bookmarked in the background without having to go through the popup submission process.

Any ideas much appreciated.


Friend asked me to create such bookmarklet and I did it, so I will share my code with others, who end up here seeking for existing solution. First of all - mentioned above sig value is some kind of key/token, signature associated with Google account that user is logged in (in order to use Google Bookmarks) - and it's always the same value (for one account). You have to find this value and copy-paste it to bookmarklets below. Just view the source of this unwanted popup page and search for /bookmarks/mark?sig= or use bookmarklet that shows hidden fields.

First version I wrote creates simple form (like the one in popup) in a new window (tab) and submits it. After that window is closed. Here goes the code:

javascript:(function(){
 var dloc = document.location;
 var dtitle = document.title;
 var code = '<html><head>
  <script src="https://www.google.com/bookmarks/history.js"></script></head><body>
  <script language="javascript">function addp(p) {document.add_bkmk_form.action = document.add_bkmk_form.action + "&" + p; return true;}</script>
  <form name="add_bkmk_form" action="https://www.google.com/bookmarks/mark?sig=_______________________&hl=pl" method=post target="_self">
  <input name=title type=text style="width:100%" id=bkmk_n value="' + dtitle + '">
  <input type="text" dir="ltr" style="width:100%" name="bkmk" id=bkmk_u value="' + dloc + '">
  <input name=labels autocomplete=off type=text style="width:100%" id=bkmk_label_1 value="">
  <input type="hidden" id="rbkmk_label_1" value=""><br>
  <textarea rows=4 style="width:100%" name=annotation style="font-size:smaller"></textarea>
  <input type=hidden name=sig value="_______________________">
  <input type=hidden name=prev value="/mark">
  <input type=submit name=btnA style="font-weight:bold" onclick="return _validate_add_bkmk(document.add_bkmk_form) && addp(\"btnA\")" value="Dodaj zakładkę">
  </form>
  <script language="javascript">document.getElementsByName("btnA")[0].click();</script>
  </body></html>';
 wnd=window.open("","wnd");
 with(wnd){
   document.write(code);
   document.close();
 } 
})();

Instead of ___________ you have to place your sig value. I should probably tidy up the code, remove style, some other attributes and unused fields, use English caption on "Add bookmark" button, delete &hl=pl suffix, etc. And maybe copy only those functions from google's history.js that are used, but don't have time for that.

Person that requested this bookmarklet didn't fully like it's behavior - i.e. that it opens new tab/window for a moment and then (auto)closes it, but there is solution for that too.

Thankfully Google's form can be also send using GET method (instead of POST), so whole action of adding bookmark maybe performed by opening URL like the one below:

https://www.google.com/bookmarks/mark?title=STACKOVERFLOW&bkmk=http%3A%2F%2Fstackoverflow.com%2F&labels=&annotation=&sig=___________________________&prev=%2Fmark&btnA=Dodaj+zak%C5%82adk%C4%99

- again replace sig value with the one found before and maybe change Dodaj+zak%C5%82adk%C4%99 to Add bookmark or whatever this button is called in google interface using your language. In bookmarklets below I will also move bkmk variable (with site address) to the end of URL for better handling ampersands and some other special characters.

This URL can be opened in new window/tab and then immediately closed and it will add google bookmark - but to achieve this without any popups, new windows/tabs we have to use little trick and add for example image with src set to this URL - like it's done in code below:

javascript:(function(){
  var gburl = 'https://www.google.com/bookmarks/mark?labels=&annotation=&sig=_____________&prev=%2Fmark&btnA=Add+bookmark&title=' +encodeURIComponent(document.title)+'&bkmk=' +encodeURIComponent(document.location);
  var f=window.frames;
  if(f.length>0 && Object.prototype.toString.call(document.body)==='[object HTMLFrameSetElement]'){
    f[0].document.body.innerHTML+='<img src="'+gburl+'" style="visibility:hidden" />';
  }
  else
  {
    document.body.innerHTML+='<img src="'+gburl+'" style="visibility:hidden" />';
  }
})();

Image is added at the end of document (or at the end of first frame if page is using frameset). It's set to be invisible, so it should not spoil anything.

Amazingly if everything worked fine Google serves back image (star) - like it was prepared specially for my bookmarklet :-) So we can use it to check if everything went correct - by checking for example if image's width or height exists and is equal to 15 px. The test is performed 1500 ms after adding image (using setTimeout()), because browser has to download image first and set it's properties. With slower connection you may need to increase this value, with faster you can decrease it. During development of this bookmarklet in Firefox 3.6, Opera, IE and Chrome I had some versions without timeout, using conditions like: !(typeof image.width === 'undefined') and in some cases > 0, in some ≥ 0 or just == 15 - but in almost each browser had to check different things... Version with timeout seems to be most universal. So my final code is:

javascript:(function(){
  var gburl = 'https://www.google.com/bookmarks/mark?labels=&annotation=&sig=_____________&prev=%2Fmark&btnA=Add+bookmark&title=' +encodeURIComponent(document.title)+'&bkmk=' +encodeURIComponent(document.location);
  var f=window.frames;
  var gbimg=document.createElement('img');
  var using_frames=false;
  gbimg.src=gburl;
  gbimg.style.visibility='hidden'; 
  gbimg.id='gb_niepowtarzalnyID_2'; 

  function test_gbed(frames)
  {
    if(frames)
    {
      if(!window.frames[0].document.getElementById("gb_niepowtarzalnyID_2") || window.frames[0].document.getElementById("gb_niepowtarzalnyID_2").width!=15)
      {
        alert("Warning!!! - page probably hasn't been bookmarked (frames)");
      }
    }  
    else
    {
      if(!document.getElementById("gb_niepowtarzalnyID_2") || document.getElementById("gb_niepowtarzalnyID_2").width!=15)
      {
        alert("Warning!!! - page probably hasn't been bookmarked (no frames)");
      }
    }
  }

  if(f.length>0 && Object.prototype.toString.call(document.body)==='[object HTMLFrameSetElement]')
  {
    using_frames=true;
    /* f[0].document.body.innerHTML+='<img id="gb_niepowtarzalnyID_2" src="'+gburl+'" style="visibility:hidden" />'; */
    f[0].document.body.appendChild(gbimg);
  }
  else 
  {
    /* document.body.innerHTML+='<img id="gb_niepowtarzalnyID_2" src="'+gburl+'" style="visibility:hidden" />'; */
    document.body.appendChild(gbimg);
  }
  setTimeout(function(){test_gbed(using_frames)}, 1500);
})();

Some final thoughts, ideas, notes:

Instead of just showing alert, it is possible to add code from a very first bookmarklet in this topic, the one with unwanted popup - because error usually means, that user is not logged in and then popup will display login form.

I've fully tested it only on Firefox, on other mentioned above browsers I checked it superficially.

In last bookmarklet I've replaced fast (but ugly) innerHTML modifications with more elegant way of creating image node and appending it to document's body.

On some pages (like: this one) Firefox doesn't even try to download image added to document body (even when visible). I didn't find the cause of it. And for example it works fine on Opera.

If your browser caches secure content (images) you might also need to add timestamp to the URL (gburl=.......... + '&myts=' + new Date().getTime();), in case you want to bookmark again already bookmarked page.

Different approach: it should be very easy to create userscript (for Firefox with Greasemonkey extension and for Chrome, Opera) that just automatically submits the form in popup - instead of using modified bookmarklet.

To cleanup after bookmarklet's job is done one can remove image from a DOM (in *test_gbed()* function).

PS: I'm aware I could optimize and compact a bit code of my bookmarklets, but I left it this way for better readability.


I'm going to have to say no. Since the page with the token in it is (presumably) on a different domain from whatever page the user is on (which is the context in which the bookmarklet runs), the cross-site restrictions would prevent the bookmarklet from scraping the token out of the page.

Therefore, in order for you to be able to do this, Google would have to provide some other mechanism, but any mechanism that would allow your bookmarklet to bookmark a page without prompting would presumably also allow unscrupulous webpages to do the same. Obviously, that is not desirable (except to would-be bookmark-spammers), so presumably Google does not provide any such mechanism.

(If bookmarklets were somehow exempt from XSS restrictions, it might be possible.)

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜