Temporary test page

The action format has been modified to stop problems with " - now uses attribute=^"setting"^

Simple Standard command with no quotes:

Test1

Standard command using double-quotes:
Test 2

Standard command using single-quotes (currently breaks as Opera does not accept single quotes in the commands themselves - in JS within a command it is fine):
Test 3

Bookmarklet test, single quotes:
Test 4

Bookmarklet test, double quotes:
Test 5

Bookmarklet Wrapped in button test:
Test 6

Kill Bookmarklet - just the bookmarklet

Kill Button - wrapped in a button

Originally opbut encodeed most characters using PHP rawurlencode() - then it had to further encode single quotes, and then unencode % 3A back to colon (:) as it breaks Opera's ability to recognise javascript. But it now sems that entity escaping is more compatible than hex escpaing

the code for encoding:

<?php
//actually decided to use entity encoding instead - more robust
$url=preg_replace("/\&/","&",$url); //replace & in url 
$url=preg_replace("/\"/",""",$url); //replace " in url
$url=preg_replace("/\</","<",$url); //replace < in url
$url=preg_replace("/\>/",">",$url); //replace > in url
//$url=preg_replace("/\'/","'",$url); //replace ' in url
?>

Add CSS Styles Console - by Aleto

Add CSS Styles Console - by Aleto


Yes bm
Yes button 1
Yes button 1 - only > not "
Yes button 2

The Yes bm is a very simple and little bookmarklet that does have > and " in its code. Click on it to see it working. very simple, huh?

Now drag it to any toolbar (not Personal Bar). Opera will create a little button that calls that bookmarklet. Easy. The code Opera generates in toolbar.ini is equal to Yes button 1. Click on newly created button. Good, it (still) works.

Now, reload the toolbar setup. The easiest way of doing this (without restarting Opera) is going to Preferences -> Toolbars and menu and trying to re-apply current toolbar.

After you reload the toolbar setup (note that we did NO change since adding the button), that button stops working. Beautiful, huh?

You may also try to drag or click on Yes button 1 or Yes button 2. Opera will add truncated entries at toolbar.ini. The entries will be truncated at second double-quote for each parameter. Of course, those (truncated) buttons won't work.

You may try to add the button code directly to toolbar.ini. Do it and note the button won't work.

What I can understand from all of this (note, some "deep Opera source code thoughts" below):

  1. When dragging a normal link (not opera:/button/ one) to a toolbar, Opera code will...
    • Create a new Button object in memory.
    • Put Go to Page as string in first parameter.
    • Put the raw link as string in second parameter. No check is done about string contents, the URL (or URI?) is simply copied as is.
    • All other parameters will be blank.
  2. When saving the previously created button, Opera will...
    • Write the button identifier string (for example: Button11?,), followed by a space.
    • Write the button name inside double quotes, followed by = character.
    • Write a double-quote (mark the start of button code).
    • Write the first parameter as string (no quotes after o before it), followed by a comma and a space.
    • Write the second parameter as string, enclosed in double-quotes. Again, there is no special treatment about the string contents. (hum... If the string had a '\n' in it?) <- The bug is here!
    • If there were other non-blank parameters, they would be printed too, with the needed commas.
    • Write a double-quote (mark the end of button code).
  3. When loading a button from toolbar.ini, Opera will...
    • Parse the things before = character.
    • Get the string between the first and last double-quote after = character.
    • Pass this string to button parser (or button constructor). I think the same happens with opera:/button/ links.
    • The button parser will get the first parameter as everything from start of string until the first comma.
    • If the character that follows (discarding whitespace) the comma is a double-quote, then the second parameter will be everything inside the first double quote (the one just after comma) until the second double-quote. <- The bug is here!
    • What will happen with other parameters isn't very relevant. (hum... If there is a comma after second double-quote, but enclosed in another double-quotes? The third or fourth parameter will start here?)

Solutions?

  1. First one would be write something like this: Go to page, "javascript:if(3>2)alert('Yes'+%22?%22);, but this don't work, because % is passed to URL interpreter, and then passed to javascript interpreter. In other words, there no automatic (un)escaping is done.
  2. Use some other escaping technic for double-quotes, but this needs a change in Opera source code. In my opinion, this is the best solution.
  3. Use a quick and dirty solution: Go to page, "javascript:eval(unescape('Escaped JavaScript code here'));. Example:

Yes button 3
If you want to keep the code a little more clean and readable, the "Escaped JavaScript code" could have only %, \, ' and " characters escaped, like these:
Yes button 4
Yes button 5

I don't know why, but this quick and dirty solution isn't working (and I think it should work).


Some new ideas... (I hope I am not mistaken)

%-escaping for javascript: bookmarklets don't work... I feel that %-unescaping isn't made for this type of URLs, so, the JavaScript interpreter receives a string full of %.

%-escaping, however, is unescaped for buttons (opera:/button/). This is a bit inconsistent, but could also be the best behavior (lots of webmasters write javascript: without %-escaping it, so, %-unescaping will break them).

You may see this behavior when you Copy link address. Note that %-escaping is automatically done when copying opera:/button/ URLs.

This explains why my "quick and dirty" solution doesn't work. The solution? Replace all % with %-escaped. This way (I hope), everything should work.

Yes button 5 - reloaded

No, it does not work, and does not work in a VERY misteryous way (I think this must be Opera bug). The Javascript that is passed to interpreter is this: javascript:eval(unescape('if(3>2)alert(7Yes7+2?2);')); This will NEVER work... It looks like Opera replace the first and the second characters of a %-escaped character (example: %22) by the unescaped character, and leaves the third character intact. This is WRONG. This will NEVER work.

Why does it try to unescape it? Simple: "go to page" action will receive a %-escaped URL, so, I think "go to page" will unescape it before processing. This is a bit inconsistent with the behavior of URLs inside <a href=" ">. In addition, the "go to page" unescaping is done VERY wrong...


NonTroppo: The reasons are still not clear to me - and I can't get a clearly defined test case up - do you think it is a combination of %-escaping being applied to only buttons and this clashing with what in the javascript?

Why does some buttons work (Kill bookmarklet as button above) whereas others (Aleto's CSS console) don't - they are BOTH %escaped in the button code. What is different that is breaking one? By breaking I mean Opera generates an illegal address for the second one - it doesn't even make it to a toolbar. What is the smallest bookmarklet we can get to break?

Can we get a simple test case?


OK, thanks to scipio - it seems there is a byte limit to opera: URLs (and maybe URLs in general?). Remember the values here are raw bookmarklets, these are then character and URL encoded, and I think this is also counted into the limit. Scipio suggests the limit is 974 bytes.

Test 53 - 53 chars

Test 287 - 287 chars

Test 415 -415 chars

Test 518 -518 chars

Test 621 -621 chars

Test 724 -724 chars broken

Test 827 -827 chars broken

Submitted as bug-162317 —{NonTroppo @ 30 Jan 2005 16:12 GMT}

There are 50 comments on this page. [Display and/or add comments]