The One with the Thoughts of Frans

Archive for Opera

Web Apps Opera Bork Edition

It’s been 18 years since Opera published their classic bork edition, to protest that MSN would have loaded properly in the browser if only it were served the same code as Internet Explorer.

“Hergee berger snooger bork,” says Mary Lambert, product line manager desktop, Opera Software. “This is a joke. However, we are trying to make an important point. The MSN site is sending Opera users what appear to be intentionally distorted pages. The Bork edition illustrates how browsers could also distort content, as the Bork edition does. The real point here is that the success of the Web depends on software and Web site developers behaving well and rising above corporate rivalry.”

Since I’m a Vivaldi user, today’s the first time I noticed that Chrome on Android artificially restricts installing webpages as apps on the homescreen. Only webpages that specify a manifest.json can receive such a hallowed treatment, instead of every single webpage ever made. For the rest of the internet, there’s only a shortcut. While the situation is not quite comparable, I found the design principle sufficiently distasteful to revive Opera’s classic bork script, in this case specifically targeting the Chrome browser.

You can put it on your website or in your TamperMonkey to remind you when you accidentally open Chrome. The classic result looks like this:

A borked Vivaldi announcement as seen in Chrome.
// http://web.archive.org/web/20050301075735/http://www.opera.com/js/bork/enchefizer.js

/* -*- mode: C++; mode: font-lock; tab-width: 4 -*-
 * 2003-02-10
 *
 * The Enchefizer code is based on a script fetched from 
 *   http://tbrowne.best.vwh.net/chef/
 * written by Andriy Rozeluk , which is
 * based on a Java version written by Josh Vura-Weis
 * , which is based on a UNIX version
 * from 1993 written by John Hagerman  and
 * Jeff Allen 
 *
 * Subsequently hacked by Opera Software to work inside a page by 
 * traversing the DOM tree, and to improve performance. 
 *
 * Typical usage is to add the following text to the bottom of a page:
 *       
 */

const classicOperaBork = () => {
    /* USER CONFIGURATION BEGINS */
    var victim=false;   // false (apply to any page) or regex to match page URL
    //var victim=/^http:\/\/(?:(?:www|msdn).microsoft.com|www.msn.com)/;
    var delay=50;       // ms between replacements, set to 0 to disable waiting
    var units=30;       // number of text nodes to translate each time
    var highlight=true; // highlight the text we're working on
    /* USER CONFIGURATION ENDS */

    var textnodes=[];   // text nodes in the doc
    var nextnode=0;     // next node to process

    function nextWordPos(line)
    {
		var p = line.search(/[ \n\t\\,<.>/?;:\'\"\[{\]}|=+\-_!@#$%^&*()~`]/);
        return p == -1 ? line.length+1 : p;
    }

    function encheferizeLine(line)
    {
		var buff="", word="", t="", out="", wp;

		while(line.length > 0)
		{
			wp = nextWordPos(line);
			word = line.substring(0,wp);
			t = line.charAt(wp);
			line = line.substring(wp+1,line.length);
			out = out + encheferizeWord(word) + t;
		}
		if(t == ".")
		{
	        out = out + "\nBork Bork Bork!";
		}

		return out;
    }

    function encheferizeWord(word)
    {
		if(word.toLowerCase() == "bork") return word;
      
		var letter, count, len, buff, i_seen, isLast;
      
		count=0;
		len=word.length;
		buff=""
		i_seen=false;
      
		while(count0){
               
				} 
			} else if(letter=='t'){
				if(count==len-2 && word.charAt(count+1)=='h'){
					buff = buff + "t";
					count+=2;
					continue;
				} else if(count<=len-3 && word.charAt(count+1)=='h'
						  && word.charAt(count+2)=='e'){
					buff = buff + "zee";
					count+=3;
					continue;
				} 
			} else if(letter=='T' && count<=len-3 && word.charAt(count+1)=='h'
					  && word.charAt(count+2)=='e'){                                                
				buff = buff + "Zee";
				count+=3;
				continue;
			} else if(letter=='v'){
				buff = buff + "f";
				count++;
				continue;
			} else if(letter=='V'){
				buff = buff + "F";
				count++;
				continue;
			} else if(letter=='w'){
				buff = buff + "v";
				count++;
				continue;
			} else if(letter=='W'){
				buff = buff + "V";
				count++;
				continue;
			}
			//End of rules.  Whatever is left stays itself
			buff = buff + letter;
			count++;
		}
		
		return(buff);
    }

    function bork()
    {
		var limit = delay == 0 ? Number.MAX_VALUE : units;
		var start=nextnode;
		var oldc = new Array();
		var n, i, candidate;

		if (highlight)
		{
			for ( n=start, i=0 ; i < limit && n < textnodes.length ; n++, i++ )
			{
				candidate = textnodes[n];
				oldc[i] = candidate.parentNode.style.backgroundColor;
			}

			for ( n=start, i=0 ; i < limit && n < textnodes.length ; n++, i++ )
			{
				candidate = textnodes[n];
				candidate.parentNode.style.backgroundColor = 'red';
			}
		}

		for ( i=0 ; i < limit && nextnode < textnodes.length ; nextnode++, i++ )
		{
			candidate = textnodes[nextnode];
            candidate.replaceData(0,candidate.length,encheferizeLine(candidate.data));
		}

		if (highlight)
		{
			for ( n=start, i=0 ; i < limit && n < textnodes.length ; n++, i++ )
			{
				candidate = textnodes[n];
				candidate.parentNode.style.backgroundColor = oldc[i];
			}
		}

		bork_more();
    }

    function bork_more()
    {
		if (nextnode < textnodes.length)
		{
			setTimeout( bork, delay );
		}
    }

    /* In large docs traversal is a bottleneck at startup; we could
       CPS it or otherwise reify the traversal state to interleave
       traversal with the translation.
	*/
    function find_textnodes(elm, acc)
    {
		if (elm.nodeType == 3)
		{
			if (!elm.data.match(/^[\s\n\r]*$/))
			{
				acc.push(elm);
			}
		}
		else
		{
			var c = elm.childNodes;
			for ( var i=0 ; i < c.length ; i++ )
			{
				find_textnodes(c.item(i),acc);
			}
		}
		return acc;
    }

    /* run page's onload handler, then do our thing */
    var res = false;

    if (typeof old_onload == "function")
	{
		res = old_onload();
	}

    if (/*window == top &&*/ (!victim || window.location.href.match(victim)) )
    {
		textnodes = find_textnodes(document.body, new Array());
		nextnode=0;
		bork_more();
    }
    return res;
}
if (window.navigator.userAgentData.brands.filter(e => e.brand === 'Google Chrome').length > 0) {
    document.addEventListener('DOMContentLoaded', classicOperaBork);
}

CommentsTags:

Stop Hijacking Annoyances

Here’s another rescue from My Opera. The script was compiled by the user pehage on February 3, 2012, after a quick pointer by me. It is Opera UserJS, so it won’t work in any other browser. Don’t forget to enable User JavaScript on HTTPS if you so desire. In Opera 12 it no longer pops up a warning all the time.

// ==UserScript==
// @name Stop Hijacking Annoyances
// @include *
// ==/UserScript==

var annoyances = ["focus", "focusin", "focusout", /*"click",*/ "dblclick", "mousedown", "mouseup", "mousemove", "mouseover", "mouseout", "mouseenter", "mouseleave", "select", "submit", "keydown", "keypress", "keyup"];

for (var i=0; i<annoyances.length; i++) {
	//opera.postError(annoyances[i]);
	window.opera.addEventListener("BeforeEventListener." + annoyances[i], function (e) {
		e.preventDefault();
		//opera.postError(e);
	}, false);
}

And here is a simple testcase I created.

<!DOCTYPE html>
<html>
<head>
<title>keypress hijacker</title>
<script>
document.addEventListener('keypress', function(e){alert('document.addEventlistener on keypress ' + String.fromCharCode(e.which))}, false);
window.onkeydown = function(e){alert('window.onkeydown ' + String.fromCharCode(e.which))}
</script>
</head>
<body>
This page hijacks keypress events in order to display an alert message.
</body>
</html>

Comments

Textarea Backup Localstorage v1.21

I figured I’d drop a note that I updated my Textarea Backup UserJS last month. What follows is the description from ExtendOpera.


Textarea Backup Localstorage

Retains what you type into textareas and contentEditable elements.

This script is only compatible with Opera 10.50 and up. If you need to use it with an older version use Textarea Backup but be advised that it comes with some disadvantages.

  1. Can automatically place previously typed text in textareas.
  2. Can add an unobtrusive menu in the top right corner of textareas

Actions menu screenshot (note the transparent object in the top right corner of the textarea):

Development can be followed on GitHub. Don’t be shy, open an issue or send me a pull request if you think you have something to contribute! 😉

Changelog

1.21 July 25, 2013. Sorry, I was a bit hasty about that last one. I passed my testcase, but only noticed that many contentEditables work differently in practice on this very site.

  • Fixed a bug that occurred when BODY was contentEditable, as is typical in iframes.
  • Properly compare initial value of contentEditable element to backed up value so you’ll only get prompted to overwrite when relevant.
  • Full changelog.

1.20 July 25, 2013. I wasn’t going to make yet another release in three days, but these new features could be implemented much faster than I initially predicted.

  • Trustworthy old persistent preferences support added. I also uploaded a sample settings file.
  • Fixed the keep_after_submission bug, so setting it to false is safe again.
  • Removed the form requirement.
  • Support contentEditable. This is a pretty big one, seeing how it was the most obvious missing feature.

1.11 July 24, 2013. Added configuration switches for the new feature.

  • For Opera 11.6x and Opera 12.x it now defaults to off because of potential performance concerns.

1.10 July 23, 2013. Added support for dynamically added textareas.

  • This new feature will only work in Opera 11.6x and up.

Comments

How To Fix SVG Height in Webkit/Blink

It’s pretty simple: also specify a height if you specify a width. To quote from the workaround in my stylesheet, which I added on account of my previous post:

figure svg {
	width:100%;
	/*what follows is because Webkit/Blink is broken https://bugs.webkit.org/show_bug.cgi?id=68995*/
	height:100%
}

I really shouldn’t have added that as I don’t cater to broken browsers anymore, but I have a bit of a soft spot for Opera—even if it’s never required any workarounds before. Presto is clearly superior, and so is Gecko. Chromium still doesn’t support SVG favicons. Gecko does. And just look at this table. Unfortunately Gecko doesn’t support SVG fonts, so it’s all looking pretty miserable without Presto.

Comments (1)Tags:

Why Opera’s XHTML Error Handling Is Superior

I found this old, unfinished post in my drafts. I’m not quite sure when I originally wrote it, but it was over a year ago. Rather than updating the content I decided to publish it as is, as I’m not sure why I didn’t, with a small addendum at the end.


I made a little compilation of the various error messages displayed by browsers upon encountering an XML syntax error. Firefox (Gecko) has the unfriendly looking error on top, Chromium (Webkit) renders the page up to the error, but shows a large error message (albeit not at all useful like in Opera & Fx), and for Opera I included 10.10 and the latest 10.50 pre-alpha build. Note that it’s just the styles behind the error message that changed a bit: the content and helpfulness of the error message is still the same. I’ll run it down a bit more:

  • Firefox displays an error message that’s only useful if you already know sufficiently much about X(HT)ML, whereas Opera’s error message not only highlights more clearly where parsing failed — although ultimately this difference might just be one of preference. More important, its error message might just helpfully link you precisely where you need to go to learn how to avoid it. When I first started messing about with XHTML back in ’03 or so, I probably would’ve appreciated it if Opera had done that. At the time Opera behaved the same as Fx does now.
  • Chromium displays an error message that doesn’t even manage to clearly indicate what’s the problem. This compares negatively to Fx and Opera highlighting the &.
  • Chromium renders the page up to the problem, which may result in a get out of jail free card. The error message doesn’t seem very annoying, but if the error is in the middle of the page it’ll still be in the way. In my sample page it’s at the end, however. (My example page is basically a standard installation of phpGraphy on which I decided to switch to application/xml+xhtml because it claims to be more or less XHTML compliant now — I had to fix all the unclosed meta and link tags first.)
  • Despite rendering the page, you won’t be able to see the page fully in Chromium. You will with Opera’s reparse as HTML function.

I hope that clarifies why I think Opera’s handling is best, both as a user and as an author.


This blog post is now outdated. You can return to the behavior I hailed by disabling the opera:config#UserPrefs|AutomaticallyreparseXHTMLwithparsingerrorsasHTML option.

Comments

Opera 11 Addressbar Revisited

I already wrote down some thoughts about the addressbar changes in Opera 11 a few days ago, and it got me thinking that the addressbar could definitely be improved, just not by detracting from it.

To cut to the chase, here’s the addressbar I’m envisioning:

What you see on this screenshot, however, does not tell the whole story. Let’s start with what’s visible:

  • The protocol is grayed out. This is the method that most so-called URL highlighting uses to emphasize the domain. I think this is the wrong approach, but in the case of the protocol it seems the right thing to do. It is somewhat hidden, but still fully visible: no need to select the addressbar to find out what protocol is being used. People know that something is a web address when they see it in print thanks to the protocol, even if they have no idea what it means (and in fact many might mistakenly interpret HTTPS as safe), and combined with the large, clear button indicating security information you’d really have to try to misinterpret HTTPS as safe.
  • The domain is highlighted, specifically by bolding in this example, but it could also be done through underlining, a background color, or a combination of various things. The important part is that the domain is highlighted, rather than the rest of the URI lowlighted.
  • Query strings have parameter highlighting, and characters that separate parameters like ? and & are hidden and replaced by a small outline indicating what goes with what. The space between the various parameters corresponds to the size of the hidden ? or & characters and thus no shifting will occur when selecting them. I did not look into things like color blindness and the colors I used are solely for illustration purposes; they are no suggestion for specific colors.

Then, what’s not visible:

  • Complex query strings, meaning with 3 or 4 parameters or more, could be hidden from that point on, but this should be visibly indicated. An ellipsis is the standard method of conveying such information, so there’s no need to come up with something fancy. A complex query string like Google’s would thus look something like http://www.google.be/search [client=opera] [rls=en] [q=test]…

    Perhaps the number of parameters before hiding occurs should be configurable as well.

    This hiding should not affect links to IDs like #someID, which are hidden along with the query string at the moment.

  • Linkify URI segments on hover when a modifier key, such as Ctrl or Shift, is pressed. This has been implemented quite nicely by the Firefox extension Locationbar².

That’s about it for my proposal regarding how to truly upgrade the addressbar as opposed to trying to make it little more than a domain display.

Comments (4)

What’s Wrong With the Opera 11 Address Bar, And How to Fix It.

Opera 11 made some drastic changes to the addressbar. I think the thought is good, but the execution leaves quite a bit to be desired.

Opera 10.63

Here you can see the classic method as it is in 10.63: full URL. You could say that the security information is somewhat detached on the right.

Opera 11

This is Opera 11, with the changed addressbar. The favicon is removed, the protocol and query string are hidden, and the security information is made more prevalent.

Generally speaking I don’t care too much about http vs. https; secure vs. insecure certainly is a better way of presenting that, lest https give you a false sense of security. Then again, I think that keeping the protocol and simply moving the security indication to the spot of the favicon (while still getting rid of that) would’ve accomplished the same effect better without losing out on such information. After all, if I notice some site uses https, but is insecure, I should probably notify the site, right? The lack of something like ftp is slightly more annoying, but the lack query strings is the absolute worst. I realize that some query strings can be overly complex, but I fail to see why the lowest common denominator should get rid of the good query strings as well. Seeing or not seeing it is only part of the issue: it also kills the ability to easily select the relevant part of the query string that you want to change (like a search term).

Opera 11 as it should be

And here is my combination of both. Remove the favicon, which might give a false sense of being on the real site (and is already visible on the tab), and move the security information to where the favicon used to be. The rest of the URL can remain fully accessible, displaying information for those who can use it. Domain highlighting can take care of those who have trouble spotting the domain they’re on (and on Windows it already does, making the removal of the query string even more peculiar). No extra step is necessary to select parts of the URL.

I feel that this is a fair compromise: it makes the security information more accessible without compromising existing functionality.

Comments (1)

Damn, It Is Cold

Weather in fall always comes paired with temperature drops, fall storms, and lots of rain. But seldom did the temperature drop from 20°C to a mere 7°C from one day to the next.

The release of Ubuntu 10.10 coincided with this change for wintry weather; however, while I’m sure it’s swell, you won’t see me upgrading just yet. Perhaps I’ll have to look a little harder into acquiring a netbook so I can use it with the Ubuntu Netbook Edition.

Of more interest is the announcement that Opera 11 will have extensions. Or, more particularly, that I was the first to guess this in a contest.

Comments

How to Disable Opera Speed Dial

As far as I’m concerned there are two reasons for disabling speed dials: it’s faster, and your history doesn’t misbehave.

The speed is less relevant since Opera 10, although more relevant again since Opera 10.50. The history argument is far more important to me. It really throws me off that the first page I visited in a window still allows me to go back. I don’t know why someone would want to go back to the speed dial; isn’t it faster to just open a new one?

To disable the speed dial, you have you change the SpeedDialState setting in opera:config.

0: Folded
1: Shown
2: Read only, and always show speed dial
3: Disable speed dial

Set it to 3 to disable speed dial completely. If you think this will impair your ability to open pages quickly and easily, you need to take note of go to nickname (Shift + F2).

Comments

Opera and Link Targets

If you’re like me and you aren’t particularly fond of sites opening in new tabs without your explicit command, you might be interested in activating Opera’s Ignore Target setting. This setting “Unfortunately … also disables the window.open() method, breaking the functionality of many sites,” so you might prefer to utilize JKing’s UserJS which stops most links from opening in new windows.

On the other hand, you might prefer all links to external sites to open in a new tab. I recently wrote a script that does just that for someone on the MyOpera forum.

Comments

Older Entries »