Showing posts with label Greasemonkey. Show all posts
Showing posts with label Greasemonkey. Show all posts

Friday, September 7, 2012

Manipulating page styles with the new Greasemonkey

This article assumes that the reader knows some JavaScript and a fair share of CSS, and how to create userscripts for Greasemonkey.

The argument for using Greasemnkey is that it allows for a more straightforward implementation of user-created styles, which don't require remote storage, such as userscripts.org.


Well, as of recently, it became impossible to manipulate styles on pages with modern versions of Greasemonkey running within Firefox and SeaMonkey.

I suppose this might have happened during the transition from Firefox 12 to some newer version. Oddly, the version of SeaMonkey has always remained the same, so this should somehow have ruled out that issue. Then I began thinking of NoScript — which is about the only extension maintained well for both SeaMonkey and Firefox, and updatd accordingly — but I'm not going to point any fingers, just because I don't know what the real cause is.

So, the situation happened to me using SeaMonkey 2.5 (which I am not using often, though planning to upgrade one day) with Greasemonkey 0.9.13.1, and in Firefox 15 with about the latest modern releases of Greasemonkey (0.9.22—1.x).
Greasemonkey is officially available only for Firefox, but since SeaMonkey 2.x is not supported by many extension developers, then Philip Chee decided to modify ostensibly free software extensions originally made for Firefox to then post them at xsidebar.mozdev.org for other SeaMonkey users. Some of the extensions are modified by request of other users. So the most recent Greasemonkey version for SeaMonkey 2.3 or newer is 0.9.13.1, which is modern, but by no means the newest fare.
If you think usescripts somehow stopped working, then this is not quite so. Compared to older implementations, Greasemonkey has just evolved and so have ways to manipulate styles with usescripts. IMHO.

The traditional, or classic, way of inserting lines of style code in a Greasemonkey userscript was something like this:
document.styleSheets[0].insertRule('DIV[class=pagecontent] {width:auto !important; max-width:1014px !important;}', 0);

^ Nevermind !important, which was meant to override existing online style rules. Writing declarations with [square brackets] is also clunkier, but more reliable.

Now, there are a few things about the metadata block to remember when composing a userscript: @namespace and @grant.
  • @namespace does require that something is written for it. For the example I had, I wrote random, and it works for a test script, but the string can't be empty and has to be meaningful, per instructions given in the link.
  • With the second, I set @grant to none.
    T., 29.01.2013. update:
    @grant is a new(ish) security measure to limit API access of a script. With this it's possible to grant none (no API access) and grant GM_*, where script lines starting with GM_* are allowed. One such example is the simplified way of modifying CSS styles through GM_addStyle. To allow GM_addStyle, set

    @grant GM_addStyle

    In conclusion, this is what I think is something that I overlooked when initially writing the blog post herein.
Interestingly, I discovered that @include strings can be equipped with wildcards. This could be an age-old feature, but this saved me a bit of effort in writing userscript code:
// @include       *.wikipedia.org/wiki/*
• By not including http:// and https:// protocols, the userscript should work for domains under both;
• The asterisk * before the primary domain (separated by a dot) allows for inclusion of subdomains. Anyhoo, the new way to insert custom style blocks is this:
GM_addStyle("DIV.pagecontent {width:auto !important; max-width:1014px !important;}")
Works for me.

Tuesday, May 10, 2011

Collapsing elements in Firefox 1.0

As I was perusing Yahoo Mail Classic in Mozilla Firefox 1.0, it turned out that there was a linked block element half-blocking the sign-out link at the top of the page and in May this year, those links stopped being underlined when hovered over — this made targeting the pointer too difficult to click on the sign-out link. If I click on that block element, it will jump to a position on the page, then, somehow the block element probably moves and probably frees up the space above the sign-out link... Or whatever.

Turned out that the culprit was an invisible non-collapsed block that contained a "Skip to conent" link, which was meant for browsers like Lynx, Links, Elinks, Netscape 4.x, and other older fare (Lynx is still maintained :). This is really the fault of site coders, who instead of specifying display:none in the element's style, only specified visibility:none. The former would have collapsed the whole element, the latter only makes it invisible, but still usable and visually existent in the document structure.

If positioning is important, then one design solution is to specify a low z-index for the invisible DIV element and a correspondingly higher z-index for code that contains links (an unordered list). In CSS, z-index specifies how elements are layered with respect to each other: a higher value means that an element is above (or in front of) all other elements and a lower value (if somewhere is a higher value specified) means that the element is below, or behind higher-valued elements.

First I tried the Adblock Plus (ABP) extension, but that didn't work: ABP 0.7.0.2 is the last version for Firefox 1.0, but lacks functionality to collapse/hide elements by their id. Only the next version, 0.7.1, starts supporting this. I've written about it previously.

As I was looking for a solution, the Greasemonkey extension caught my fancy. The last to support Firefox 1.0 is 0.5.3.
Version 0.5.3 is also the last one of Greasemonkey to install on SeaMonkey 1.1, but it doesn't work.

The solution is to first install xSidebar (If the current stable versions won't want to install, then version 1.0.1 or 1.0.2 might install properly). Then on the back of xSidebar a modified Greasemonkey extension can be installed. So for SeaMonkey 1.1, Greasemonkey 0.8.2 mod is the order of the day. Note that if you have Adblock Plus 1.0.2 installed, its toolbar button will vanish. But no worries: You can turn on the Adblock Plus status bar icon from Tools > Adblock Plus Preferences...
Greasemonkey is a powerful tool to change the look and functionality of online sites and web pages client-side, but alas, it is not very easy and requires knowledge of HTML, JavaScript and CSS.

There are many instructions online on how to incorporate custom JavaScript and CSS snippets into your browser equippped with Greasemonkey and how to specify server whitelists and blacklists. I might introduce the same instructions here or put them up somewhere else.

While I thought I just had the solution, it then turned out that the block element was only equipped with a class parameter and no ID. I had also learned that only recent and modern versions of Greasemonkey now support the JavaScript getElementbyClass functionality, but I only have an outdated version.

Well, no matter: Greasemonkey 0.5.3 supports getElementbyId, but that really is not the most important thing, because Greasemonkey also allows injecting snippets of Cascading Style Sheets with JavaScript. And CSS is power.

Yes, while the DIV element did not have the ID parameter in it, it still had the CLASS parameter specified and the solution looks like this:
document.styleSheets[0].insertRule('A[class~=yucs-skipto-search] {display:none}', 0);
/* ^A is the linked element;
• Square brackets in the selector are used for conditional matching in the form of ELEMENT[attribute=value] — In this case, the {display:none} CSS block applies when yucs-skipto-search is found anywhere in an A tag's class attribute value (which the next point is about);
~= means that the pattern for the element attribute may be any matching part inside class, because when I looked at the source, the class parameter contained more than just yucs-skipto-search.
display:none collapses the element. */

document.styleSheets[0].insertRule('A[target=_top]:hover {text-decoration:underline !important;}', 0);
/* ^ In this line, Any hovered link tag A where the target parameter exactly contains _top must be underlined when hovered over. Note that instead of ~= for any matching part inside A[TARGET ]there is a single equals sign = for an exact match. !important overrides anything provided previously and makes sure that the these links are underlined when hovered over. */
So much for now.