XP1's Blog

Opera

Google+'s Missing Code for Opera (July 2011)

, , , , , , , , , , , , , , , , , , , , , , , ,

Where are the missing Google+ web toolbar features, like the notification button, share button, and the avatar? Why don't they show up in Opera? Why do they show up in other browsers?

The difference is in the code.

--- Google+'s Missing Code for Opera (July 2011) EDIT: On August 16, 2011, Google is like: "Opps, nevermind." :| EDIT: Today, this morning, on August 12, 2011, Google finally removed the Google+ server-side browser sniffing for Opera! Because the Google+ server-side browser sniffing is now gone, you can now uninstall the extension and reset your user agent back to Opera. Right click > Edit Site Preferences... > Network > Browser identification: Identify as Opera > OK. smile Introduction Where are the missing Google+ web toolbar features, like the notification button, share button, and the avatar? Why don't they show up in Opera? Why do they show up in other browsers? The difference is in the code. Compare the code Disable JavaScript, set "Mask as Firefox", and then refresh the page. Keep JavaScript disabled, set "Identify as Opera", and then refresh the page. Visually compare the differences: "Mask as Firefox" shows the notification button, share button, and your avatar, while "Identify as Opera" does not. For each time, go to the source and then save the original copies. Once you have the source code for Opera and Firefox user agents, format or beautify the code for easier comparison. If you compare the code, it is different. Turns out that Google is using server-side browser sniffing, a great evil, to serve different webpage source code, depending on the user agent. Let's look at the different parts of the code. CSS is in the beginning of the webpage source code, followed by the web toolbar HTML, and then finally ending with the JavaScript at the bottom of the source code. Part 1: Different and missing CSS Changes A few times, Google serves a different background sprite in the CSS. Served to Opera user agent:
background:url(//ssl.gstatic.com/gb/images/b_8d5afc09.png);
_background:url(//ssl.gstatic.com/gb/images/b8_3615d64d.png);
Served to Firefox user agent:
background:url(//ssl.gstatic.com/gb/images/h_bedf916a.png);
_background:url(//ssl.gstatic.com/gb/images/h8_3dd87cd8.png);
The first sprite image, served to Opera user agent, does not contain the notification images, but the second, served to Firefox user agent, does. For "#gbmpi,#gbmpid", the weight and height are different: Served to Opera user agent:
height:48px;
width:48px;
Served to Firefox user agent:
height:96px;
width:96px;
Change
#gbmpp {
display:none;
}
to
#gbmpp,.gbgsta,.gbto .gbgst,#gbns {
display:none;
}
Insertions Add this CSS:
#gbd1 .gbmc,#gbd3 .gbmc {
padding:0;
}

#gbgs1 {
text-align:center;
}

#gbi1 {
color:#fff;
display:block;
font-size:11px;
font-weight:700;
position:relative;
width:21px;
}

#gbi1a {
background:url(//ssl.gstatic.com/gb/images/h_bedf916a.png);
_background:url(//ssl.gstatic.com/gb/images/h8_3dd87cd8.png);
background-position:0 -274px;
position:absolute;
right:5px;
top:3px;
height:20px;
width:21px;
}

.gbto #gbi1a {
_background-position:-52px -274px;
top:5px;
}

#gbi1a.gbid {
background-position:-26px -274px;
}

.gbto #gbi1a.gbid {
_background-position:-78px -274px;
}

#gbi1.gbids {
color:#999;
}

#gbg3 .gbts {
line-height:20px;
}

.gbgsc {
padding-bottom:7px;
position:relative;
top:3px;
}

.gbgsca,.gbgscb {
background:url(//ssl.gstatic.com/gb/images/h_bedf916a.png) no-repeat;
_background:url(//ssl.gstatic.com/gb/images/h8_3dd87cd8.png) no-repeat;
height:20px;
position:absolute;
top:0;
width:3px;
}

.gbgsca {
left:0;
background-position:0 -300px;
}

.gbgscb {
right:0;
background-position:-153px -300px;
}

.gbgsb {
background:url(//ssl.gstatic.com/gb/images/h_bedf916a.png);
_background:url(//ssl.gstatic.com/gb/images/h8_3dd87cd8.png);
background-position:-3px -300px;
height:20px;
right:3px;
left:3px;
position:absolute;
top:0;
}

.gbgss {
visibility:hidden;
padding:0 6px;
}

.gbgst,.gbgsta {
color:#666;
padding-right:5px;
padding-left:3px;
}

.gbto .gbgsb,.gbto .gbgsca,.gbto .gbgscb {
background:none;
}

.gbgsc,.gbgst,.gbto .gbgsta {
display:inline;
}

.gbmwc,#gbwc {
right:0;
margin-top:-2px;
position:absolute;
top:-999px;
width:440px;
z-index:999;
}

.gbmsg {
display:none;
position:absolute;
top:0;
}

.gbmsgo .gbmsg {
display:block;
background:#fff;
width:100%;
text-align:center;
z-index:3;
top:30%;
}

#gbd1,#gbd1 .gbmc {
width:440px;
height:190px;
}

#gbd3,#gbd3 .gbmc {
width:440px;
height:8em;
}
If you don't apply the CSS, the displayed webpage, from the HTML below, will become garbled, and the text will appear collided. Part 2: Different and missing HTML There is one major line of HTML code that needs to be changed. However, the majority of HTML code is entirely missing and needs to be inserted into the DOM. Changes Change
<li class='gbt'><a class='gbgt' id='gbg4' href="//google.com/profiles" onclick="gbar.tg(event,this)" aria-haspopup='true' aria-owns='gbd4'><span class='gbtb2'></span><span id='gbgs4' class="gbts gbtsa"><span id='gbi4'><span id='gbi4m1'>Your name</span><span class='gbma'></span></span></span></a>
to
<li class='gbt'><a class='gbgt' id='gbg6' href="//google.com/profiles" onclick="gbar.tg(event,document.getElementById('gbg4'))" tabindex='-1' aria-haspopup='true' aria-owns='gbd4'><span class='gbtb2'></span><span class='gbts'><span id='gbi4t'>Your name</span></span></a></li>
Insertions Within "<ol class='gbtc'>", below "<li class='gbt'>", insert (as second node):
<li class="gbt gbtb"><span class='gbts'></span></li>
<li class='gbt'><a class="gbgt gbgtd" id='gbg1' href="/u/0/notifications/all" title="Notifications" onclick="gbar.tg(event,this)" aria-haspopup='true' aria-owns='gbd1'><span class='gbtb2'></span><span id='gbgs1' class='gbts'><span id='gbi1a' class='gbid'></span><span id='gbi1' class='gbids'>&nbsp;</span></span></a>
<div id='gbd1' class="gbm gbmsgo" aria-owner='gbg1'>
    <div class='gbmc'>
    </div>
    <div class='gbmsg'>
    </div>
</div>
</li>
<li class="gbt gbtb"><span class='gbts'></span></li>
<li class='gbt'><a class='gbgt' id='gbg3' href="/u/0/stream/all" onclick="gbar.tg(event,this)" aria-haspopup='true' aria-owns='gbd3'><span class='gbtb2'></span><span id='gbgs3' class='gbts'>
<div class='gbgsc'>
    <span class='gbgsb'><span id='gbi3' class='gbgst'>Share&hellip;</span><span class='gbgsta'>Share</span></span><span class='gbgss'>Share&hellip;</span><span class='gbgsca'></span><span class='gbgscb'></span>
</div>
</span></a>
<div class="gbm gbmsgo" id='gbd3' aria-owner='gbg3'>
    <div class='gbmc'>
    </div>
    <div class='gbmsg'>
    </div>
</div>
</li>
<li class="gbt gbtb"><span class='gbts'></span></li>
<li class='gbt'><a class="gbgt gbg4a" id='gbg4' href="//google.com/profiles" onclick="gbar.tg(event,this)" aria-haspopup='true' aria-owns='gbd4'><span class='gbtb2'></span><span id='gbgs4' class='gbts'><span id='gbi4'><span class='gbi4p'></span><span id='gbi4id' style="display:none"></span><img id='gbi4i' width='24' height='24' onerror="window.gbar&&gbar.pge?gbar.pge():this.loadError=1;" src="//lh5.googleusercontent.com/-0000000000/AAAAAAAAAAI/AAAAAAAAAAA/0000000/000-0/photo.jpg" alt=""></span></span></a>
Within "<div id='gbmpdv'>", above "<div class='gbpc'>", insert (as first node):
<span id='gbmpid' style="display:none"></span><img id='gbmpi' width='96' height='96' onerror="window.gbar&&gbar.ppe?gbar.ppe():this.loadError=1;" src="//lh5.googleusercontent.com/-0000000000/AAAAAAAAAAI/AAAAAAAAAAA/0000000/000-0/photo.jpg" alt="">
Of course, "Your name" is supposed to be your name, and "//lh5.googleusercontent.com/-0000000000/AAAAAAAAAAI/AAAAAAAAAAA/0000000/000-0/photo.jpg" is supposed to be your profile avatar. Once you insert this missing HTML into the DOM, you should see the notification button, share button, and your avatar in the web toolbar. However, they won't work without the JavaScript. Part 3: Different and missing JavaScript Most of the differences in the JavaScript at the bottom of the source code is just swapped, minified variable names. However, one big difference is this reference to an external JavaScript file. Served to Opera user agent:
w.push(["m", {
            url: "//ssl.gstatic.com/gb/js/sem_d8da90aa15552b1b6c43db160e9dbc9c.js"
        }]);
Served to Firefox user agent:
w.push(["m", {
            url: "//ssl.gstatic.com/gb/js/smm_07310c38d3c237229f8fe2558d96c338.js"
        }]);
The first JavaScript file, served to Opera user agent, contains 16413 characters, and the second, served to Firefox user agent, contains 50712 characters. Next, we have the missing feedback code:
var Ra = function(a)
    {
        y("uf", a)
    };
w.push(["uf", {
    url: "//ssl.gstatic.com/gb/js/fm_e6150f2ae3471582f5e836c0e2ecbb3e.js"
}]);
var Z = {};
Z.a = function(a)
{
    l.feedback.ds = a
};
Z.i = function()
{
    Ra(function()
    {
        l.feedback.startFeedback()
    });
    C("uf")
};
n("feedback", Z);
n("startFeedback", Z.i, Z);
n("dsc", Z.a, Z);
var Sa = {
    productId: "sandbar:119",
    locale: "en"
};
u.feedback = Sa;
if (_tvv(""))
{
    var $ = {},
        Ta = function(a, b)
        {
            $[a] || ($[a] = []);
            $[a].push(b)
        },
        Ua = function(a)
        {
            if (a.type) for (var b = $[a.type], c = 0; b && c < b.length; ++c) try
            {
                b[c](a)
            }
            catch (e)
            {
                o(e)
            }
        };
    n("bc", {
        subscribe: Ta,
        dispatch: Ua
    })
}
Finally, we have the missing notification and share code:
if (_tvv("1") || _tvv("1"))
{
    var Ya = {
        uo: "",
        s: "/",
        h: "/",
        po: "",
        pa: "/u/0/_/notifications/frame",
        q: "",
        f: "pid=119",
        ipd: _tvn("5", 5),
        psec: _tvn("", -1),
        it: _tvn("60", -1),
        l: "en",
        sto: _tvn("10", 10),
        mnr: _tvn("30", 0)
    };
    u.sw = Ya
}
if (_tvv("1"))
{
    var Za = [],
        $a = function(a)
        {
            Za.push(a)
        };
    n("nuc", Za);
    n("anuc", $a);
    var ab = {
        ht: _tvn("100", 0),
        n: "Notifications"
    };
    u.no = ab
}
if (_tvv("1"))
{
    var bb = [],
        cb = function(a)
        {
            bb.push(a)
        };
    n("smc", bb);
    n("asmc", cb);
    var db = {
        ht: _tvn("100", 0),
        n: "Share"
    };
    u.sb = db
}
Conclusion Like I said earlier, a lot of the minified JavaScript variable names are swapped. For example, the variable "a" could be "v" or some other character, meaning something completely different in the served Firefox code. This means that it would be a lot harder to just retrofit the JavaScript changes into the served Opera code because the variable names are not the same, and you would have to account for (hundreds of?) variable name differences. In addition to the large chunks of code above, there are a few small chunks of JavaScript code, which I have no idea what they do, scattered around. It would be a lot easier if you copy the differences, verbatim, and then replace the served Opera code by chunks entirely (no deep retrofit or changing of the JavaScript, just complete replacement).

TinyMCE JavaScript error in Opera (getRangeAt, INDEX_SIZE_ERR)

Comments

Unregistered user Sunday, July 17, 2011 6:04:29 AM

Anonymous writes: good d beptq

XP1 Sunday, July 17, 2011 5:12:36 PM

Originally posted by anonymous:

Anonymous writes:

good d beptq

I agree?

Gonçalo Fernandesilogico Sunday, July 31, 2011 11:36:29 AM

Would it be possible to make an extension to fix it?

XP1 Wednesday, August 10, 2011 4:26:28 PM

Originally posted by ilogico:

Would it be possible to make an extension to fix it?


Sure.

See:
https://github.com/XP1/Google--for-Opera/

Installation instructions:
https://github.com/XP1/Google--for-Opera/wiki/Installation

If you install Google+ User Agent Enforcer:
Go to https://plus.google.com/ > Right click > Edit Site Preferences... > Network > Browser identification: Identify as Firefox > OK.

I posted about it here in the My Opera forums:
http://my.opera.com/community/forums/findpost.pl?id=9922772

Gonçalo Fernandesilogico Thursday, August 11, 2011 1:34:22 PM

The Google+ User Agent Enforcer works very well, and the +1 button extension is also a usefull one. I think you should publish them.

Anyway, Thank you for making them.

XP1 Friday, August 12, 2011 8:34:55 PM

Because today, on August 12, 2011, Google finally removed the Google+ server-side browser sniffing for Opera, you can now uninstall the extension and reset your user agent back to Opera. Right click > Edit Site Preferences... > Network > Browser identification: Identify as Opera > OK.

smile

Gonçalo Fernandesilogico Sunday, August 14, 2011 1:02:41 PM

I noticed that yesterday smile

Nimesh nimeshthakkar Tuesday, August 16, 2011 5:41:19 PM

Google has again started browser sniffing and Google+ is back to square one.
Can you make this extension as a addon button like Surplus from Chrome web store?
https://chrome.google.com/webstore/detail/pfphgaimeghgekhncbkfblhdhfaiaipf

XP1 Wednesday, August 17, 2011 2:41:42 AM

Originally posted by nimeshthakkar:

Google has again started browser sniffing and Google+ is back to square one.

sad

Originally posted by nimeshthakkar:

Can you make this extension as a addon button like Surplus from Chrome web store?
https://chrome.google.com/webstore/detail/pfphgaimeghgekhncbkfblhdhfaiaipf

I glanced at the Surplus source code. However, I haven't come to a conclusion yet. I am still testing Surplus on Chrome.

I left Surplus running for a couple hours, and this is what happened:
http://img28.imageshack.us/img28/3199/surplusmemoryusage.png [ http://imageshack.us/photo/my-images/28/surplusmemoryusage.png/ ]

Surplus is using more than 350 MiB RAM. In total, even more physical memory used than Opera, which has over 70 tabs open, but Chrome has only 3 tabs open. bigeyes

Nimesh nimeshthakkar Wednesday, August 17, 2011 5:09:42 PM

And Google has changed the class names again so the User CSS I created is no longer working sad
This is what I hate about biggies like Google and Facebook.

One question: Did you manually expanded the javascript/css codes or used some software to do it?

XP1 Monday, August 22, 2011 6:31:41 AM

Originally posted by nimeshthakkar:

And Google has changed the class names again so the User CSS I created is no longer working sad
This is what I hate about biggies like Google and Facebook.

Yeah, every time the code is updated, it is then pushed to a minifier/obfuscator/packer, which will change everything.
I'm surprised that without an update, my Google+ Injector extension is still working.

Originally posted by nimeshthakkar:

One question: Did you manually expanded the javascript/css codes or used some software to do it?

I loaded the webpages first identified as Opera > Right click > Source > Save and also identified as Firefox > Right click > Source > Save.
Next, I used Beyond Compare to compare the source code differences side-by-side. You can use any other text compare software.

For beautification/formatting:
JavaScript or HTML: http://www.jsbeautifier.org/
CSS: http://senchalabs.github.com/cssbeautify/

Gonçalo Fernandesilogico Tuesday, August 23, 2011 11:50:32 AM

Originally posted by XP1:

Yeah, every time the code is updated, it is then pushed to a minifier/obfuscator/packer, which will change everything.



I'm pretty sure they use GWT to make Google+, which is a Java to JavaScript compiler and a GUI toolkit. It's natural that the resulting code seems deliberately obfuscated.
Also, GWT generates different versions of code for different browsers. According to Google, it works in Internet Explorer, Chrome, Safari and Firefox (and for the most part in Opera).
I think the problem is GWT.

Nimesh nimeshthakkar Tuesday, August 23, 2011 5:52:21 PM

@XP1, @ilogico - Thanks for the helpful info

Nimesh nimeshthakkar Friday, September 2, 2011 9:15:38 PM

@XP1 - Converted Surplus Lite extension into a Speed Dial extension to show Google+ notifications directly into speed dial

http://my.opera.com/nimeshthakkar/blog/2011/09/02/g-notif-speeddial-extension

XP1 Saturday, September 3, 2011 9:05:46 AM

Originally posted by nimeshthakkar:

@XP1 - Converted Surplus Lite extension into a Speed Dial extension to show Google+ notifications directly into speed dial

http://my.opera.com/nimeshthakkar/blog/2011/09/02/g-notif-speeddial-extension

Cool.up

Yours is based on my experimental version before I released version 1.0.

Nimesh nimeshthakkar Saturday, September 3, 2011 11:23:38 AM

Okay. Will check and update.

Jimtoyotabedzrock Sunday, September 4, 2011 6:41:50 PM

Originally posted by ilogico:

Originally posted by XP1:

Yeah, every time the code is updated, it is then pushed to a minifier/obfuscator/packer, which will change everything.

I'm pretty sure they use GWT to make Google+, which is a Java to JavaScript compiler and a GUI toolkit. It's natural that the resulting code seems deliberately obfuscated. Also, GWT generates different versions of code for different browsers. According to Google, it works in Internet Explorer, Chrome, Safari and Firefox (and for the most part in Opera). I think the problem is GWT.



I think they use the closure compiler http://closure-compiler.appspot.com/home

Charles SchlossChas4 Tuesday, November 15, 2011 5:21:41 PM

I also noticed the missing things when I loaded google + in Safari and saw things not show to Opera

Jimtoyotabedzrock Thursday, November 17, 2011 4:10:59 PM

Originally posted by Chas4:

I also noticed the missing things when I loaded google + in Safari and saw things not show to Opera



The best way to make it work is to use
https://github.com/XP1/Google--for-Opera/tree/master/Google+%20User%20Agent%20Enforcer/Extension

And to set it to identify as Firefox.

But certain features when you share a page from another site will not work, you can't add a comment from a third party page.

Charles SchlossChas4 Thursday, November 17, 2011 5:28:18 PM

Also use the feedback link and send lots of it wink

Have you thought of sending the extension code to Opera to use in the browserjs?

Jimtoyotabedzrock Friday, November 18, 2011 2:43:05 PM

Originally posted by Chas4:

Also use the feedback link and send lots of it wink

Have you thought of sending the extension code to Opera to use in the browserjs?

Feedback is removed if you don't use this extension lol. It's not my code and it is an incomplete solution. Many Google people have profiles on Google Plus. Some follow me but I dunno if they work on G+.

Charles SchlossChas4 Saturday, November 19, 2011 3:21:40 PM

Nope it is not removed, it is there in the bottom right

Opera is also on Goolge+

Write a comment

New comments have been disabled for this post.