Showing posts with label javascript. Show all posts
Showing posts with label javascript. Show all posts

Friday, 24 May 2013

Unreadable gibberish

*
My biggest achievement this week was undoubtedly to convert a perfectly good webpage into gibberish!

Wb rukdist anwiinojort tcas hium mes etduentidfp te luqmibt e jenkuptyj waid cahbofu ubti godwerash!

The reason you might want to do this, is when you need to focus on some other aspect of the page/prototype/design other than the content. Or if you want to use screenshots but don't want potentially sensitive content to be visible.

This little method adds 'gibberish' to a context object e.g. window, then you can run gibberish.go( element ); where element is a dom node e.g. document.getElementsByTagName('body')[0] .

Check it out...
http://clanceyp.github.io/gibberish.js/

Saturday, 20 April 2013

Simple XML to JSON

I needed to convert an xml document into json and went for the most simple implementation which just loops though the node tree and creates json object. Because the expected xml is nice and simple (nodes don't have both a text value and child nodes, they are either one or the other) I didn't really need to use anything complicated.

There was an issue though, it transpires I do need to preserve the attributes. The standard way to do this would probably be to make the attributes children of the current node and add a '#text' child to capture the original text value.


So for example the following xml...


<root>
    <item>
      <title>Porro est qui</title>
      <link>http://boom.shakalack</link>
      <author id="123">Jasmine Smith</author>
    </item>
</root>

would produce something like this...

{
  "root":{
    "item":{
      "title":"Porro est qui",
      "link":"http://boom.shakalack",
      "author": {
        "#text":"Jasmine Smith",
        "-id":"123"
      }
    }
  }
}

or this...

{
  "root":{
    "item":{
      "title":"Porro est qui",
      "link":"http://boom.shakalack",
      "author": {
        "#text":"Jasmine Smith",
        "@attributes":{
         "id":"123"
        }
      }
    }
  }
}


This kind of formatting is not going to work for me though, the fact that if an attribute is added to a xml node which didn't have one before, your json format will change makes this too risky to use. Also the issue that on some nodes you can use the value directly and on others you need to go down a level to find the child '#text' node, make this a rather messy solution.

After thinking about it I settled on a, not ideal, but fairly simple solution, appending the attribute to the current named node at the same level, so given the same xml the output becomes....

{
  "root":{
    "item":{
      "title":"Porro est qui",
      "link":"http://boom.shakalack",
      "author":"Jasmine Smith",
      "author@id":"123"
    }
  }
}

This format you can now access these attributes, for example in a mustache template you might use the following...

{{#item}}
  <details>
 <summary>{{title}}</summary>
 <div><a href="/authors/{{author@id}}/show">{{author}}</a></div>
  </details>
{{/item}}

This works quite well for me, it's simple and easy to read. One has to keep in mind that the presence of an @ symbol means you can't use dot notation though, e.g. item.author@id will not work you have to do this item["author@id"] instead, as I mentioned, not ideal!


view the xml to json javascript on github

Simple XML to JSON


Wednesday, 20 February 2013

Focus/Blur event propagation

So I'm making a dynamic menu work better for keyboard users and just thought it'd take 10 mins to add device independent event handlers to the existing code. Did that, hit Ctrl+F5 a couple of times and nothing happend.

It turns out, not all events propagate, which when you think about it makes sense. I'm using YUI for this particular project so need the focus event module, if your hand rolling you'll need use the IE focusin/focusout events, and for everything else register your event listeners in the capturing phase, check it out on quirksmode.org.





 

Wednesday, 6 February 2013

Chrome extensions don't run on first use

Okay, so I'm having this problem with my chrome extensions. The user downloads and installs an extension, clicks on the icon and boom, nothing happens! The reason being, page loaded before your extension was installed don't contain the content scripts.

As yet, I haven't found a work around but, at least, using the following you can send an alert to the page and tell the user whats happening...
/* in the background.js */

chrome.browserAction.onClicked.addListener(function(tab){ 
    linkAudit.log('alert if not loaded'); 
    chrome.tabs.executeScript(tab.id, {
     code:'if(!window.linkAudit){alert("Please reload the page to run Link Audit")}'
    }) 
});
Investigate the Link Audit extension.

Wednesday, 23 December 2009

hasLayout problems after all these years

Having terrible trouble with all version of IE trying to get some peekaboo text to stay put. In this scenario a div was not paying ball at all, after setting hasLayout on pretty much every element in the entire page I realised that the system was outputting HTML without a DTD, dogh, I feel like i've just called tech support to complain about not being able to print, only to find out that the cleaner unplugged the printer.

Note to self, always check the most obvious thing first!

In IE7 I have a normal input type = button which as the behaviour that when you scroll the text in the button gets visually corrupted. So very slowly scrolling the button into view will wipe the text and the button will appear empty. The offending button is fine in IE6 and IE8, I was tempted to ignore this and mark it down as a bug in the browser but weakened and decided to fix it.

After tinkering with the CSS for a while I couldn't find any hack/fix for this issue, setting the writing-mode style to top to bottom, did fix it but didn't think having the button text written out vertically would go down well!

In the end....


window.attachEvent ('onscroll', function(){
// layout fix for IE7 disappearing text, element has layout so resorting to this madness!
document.getElementById('buttonMoreSections').style.backgroundColor=(document.documentElement.scrollTop % 2)? '#fff':'white';
})


total MADNESS !

Wednesday, 16 December 2009

Image Replacement, but only if images are enabled

The fact that you don't know whether the user has images enabled or not is a real problem with image replacement. You can't hide the existing text if images are disabled as the user will just end up with nothing, the standard way to handle this problem is to keep the text visible and have an image bigger than the text and place the image over the text, if the user doesn't have images they will still see the text. This is only ok if your replacing a header where the image is bigger than the text, but no good for any small images like icons where the text is always going to be bigger.

One way round this is to only add images if your sure the user has images enabled and to keep the text in the HTML flow for screen reader users.

One way of testing for images is to use JavaScript and set a class name on the HTML element if image are enabled/supported, then you can apply styles based on the existence of this class name, using this technique you'll only do image replacement if the user has JavaScript, CSS and Images enabled which is a good thing. If the user doesn't have any of these three you probably don't want to mess with the UI at all.

See the image replacement test page for some uses.


Tuesday, 10 November 2009

IE, butters text after filter is applied

IE8 logo In my little world IE8 usage over took IE7 for the first time last month, so decided to try to sort out my JavaScript fades which I disable for IE. The problem with the fades is after the fade in ends the text is blurred, fuzzy and generally butters!

TODO: add image of butters text...

I haven't looked into this in any great depth, but the problem seems to be with clearType text in IE and obj.style.filter. If you apply the Alpha(opacity) filter the text gets mashed up, so setting obj.style.filter="Alpha(opacity=100)" breaks the anti-alias on text.

One work around is to set a background colour on the element your going to apply a filter to. If you don't know which elements your going to fade in advance you can reset the filter after the fade has run, which isn't ideal but better than nothing.

I user a method similar to the bellow for setting opacity

/** @id Transition.SetOpacity */
function SetOpacity(el,opacity){
opacity = (opacity>=100)? 100 : opacity;
el.style.opacity = (opacity / 100);
el.style.MozOpacity = (opacity / 100);
el.style.KhtmlOpacity = (opacity / 100);

// private method to set opacity in IE
setIEOpacity(el,opacity)

function setIEOpacity(el,opacity){
if (!el.currentStyle.hasLayout){
// give element layout
el.style.zoom = 1;
}
if (!el.originalFilter){
// save the original filter, if one exists, so you can replace it after fade
el.originalFilter = el.currentStyle.filter || 'none';
}
// if opacity = 100 put the original filter back
el.style.filter = (opacity == 100) ?
el.originalFilter :
'progid:DXImageTransform.Microsoft.Alpha(opacity='+ opacity + ')';
}
}

NB. for a fade to work in IE at all, the element needs to have layout (obj.currentStyle.hasLayout) this is a read only attribute, to set it to true you need to give the element a style that will trigger it to set .hasLayout to true. I normally set the zoom style to 1 in an IE only stylesheet. For other ways of tringering hasLayout see haslayout.net

Thursday, 26 March 2009

Mouse over menus and delay

Just been looking at menus, not for the first time nor the last. One thing i picked up on in Jakob Nielsen's Alertbox is his opinion that mouse over menus should appear after a half second delay, this is to reduce the irritating flicker you get when moving the mouse around a page. I've only seen this implemented a couple of times, can't remember where, but I totally agree with this approach.

I'm much more of a clicky menu person myself, but if you must go mouse over then, delay before showing and delay before closing too!


Related links


Saturday, 21 March 2009

JavaScript support levels

Generally, i breakdown JavaScript support into 4 levels. This makes life much easier and as i'm a lazy bas****d it suits me to keep development time down to a minimum.

I'm using something like this...


window.user = {
jsSupportLevel : 0,
init: function(){
if(!document.getElementById){return;}
var ua=navigator.userAgent.toLowerCase();
var platform=navigator.platform.toLowerCase();
var isPC = (platform.match('win32')||platform.match('win64'))?true:false;
var isDeskTop = ( ua.match('firefox') || isPC || platform.match('macintel') )?true:false;
var support = 1;
if (window.XMLHttpRequest){support = 2}
if ( support==2 && isDeskTop ){
support = 3;
}
this.jsSupportLevel = support;
}
};user.init();


This will give you a js global "user" and you use it in your js to determine whether to do some enhancements or not.
e.g.
if (user.jsSupportLevel>1){
... attach Ajax related event handlers ...
}


Example support levels

0 = user-agent doesn't understand DOM (!document.getElementById)
1 = user-agent DOM enabled
2 = user-agent has native ajax support (window.XMLHttpRequest)
3 = user-agent is probably a desktop browser

You can use the above to deliver the appropriate level of JavaScript support to users, e.g. Don't implement any JavaScript if the support level is 0, only do very basic JavaScript for level 1, do pretty much everything for level 2 and level 3 is level 2 with transitions and opacity (stuff you wouldn't want on a mobile/hand-held).

This will only work if your using progressive enhancement of course!

Friday, 27 February 2009

Is the NoScript tag the tag of the devil?

I came to the realisation today that the noscript tag is the sporn of the devil. It encourages developers to think of JavaScript in black and white, it's either on or off, the users support it or they don't. Unfortunately this simplistic approach can leave your users frustrated and thinking your site is broken. Consider this over heard conversation...


Project manager:
"Why doesn't the site work on my Blackberry?"
Developer:
"We don't support the Blackberry"
Project manager:
"but I thought you said it works without CSS and JavaScript?"
Developer:
"yes it works fine without CSS and JavaScript, we've built it in semantic HTML"
Project manager:
"so it should work on anything that understands HTML?"
Developer:
"... yes ..."
Project manager:
"so why doesn't it work on the Blackberry??"
Developer: ".... err ....


The NoScript tag has struck, pretty much all user agents support JavaScript. Much better to use progressive enhancement instead.

Consider this:


<noscript>
<p>
Important information for users without JavaScript
</p>
</noscript>
<script type="text/javascript">
if (document.getElementById){
// do funky things
...
}
</script>



We have just created a crack down the back of the sofa which has swallowed every user-agent that supports javascript but doesn't support document.getElementById or doesn't get the JavaScript in the first place. These users don't get the JavaScript enhancement and they don't get the noscript fallback : (

Tuesday, 24 February 2009

Are images enabled?

If your not sure what image replacement is, it's a technique to replace a bit of text (often an H1 level header) with an image. It's not really a very good idea, for one thing it creates a no fall back situation, e.g. you hide the text and put in a nice background image, which, if images are disabled the user can't see (oops!) and since it's a background image there is no alt text, hence no fall back, just an empty space.

So what to do? Using progressive enhancement you wouldn't want to implement something unless you know it's supported, you can use JavaScript to test if images are enabled and then add a class name to the html tag is one way to go.

Browsers seem to fall into two camps when images are turned off. Ones that don't load images at all and ones that load all img tags with an empty image. So you need to create two tests, first attach an onload function to an image you know exists, this will not fine on browsers that don't load images at all.

e.g...

var existentimg = new Image;
existentimg.onload = function(){
// if this didn't fine, images aren't enabled
}
existentimg.src = "know_to_exist.png";



As the above will fire on browsers that load images when images are disabled you need to do the same test again but this time attach the onload to an image you know does not exist.

e.g...

var nonexistentimg = new Image;
nonexistentimg.onload = function(){
// if this fires, images are disabled
}
nonexistentimg.src = "/nonexistent.gif";



I've put an example function at the bottom of this page that combines the two functions.

What to do with the info when you have it? Once you know if the user-agent has images enabled you can add a class name (e.g. "img") to the HTML tag, this will provide a way of using the information in your CSS.

e.g...

/* these styles will only be implemented if images are enabled */
html.img h1 {background-image:url(H1.png);width:XXXpx;height:XXpx;}
html.img h1 span {position:absolute;left:-9999px;}


Anonymous JavaScript function example, run this on DOM ready


(function(existingimageurl){
var existentimg = new Image;
existentimg.onload = function(){
document.getElementsByTagName('html')[0].className+= " img";
var nonexistentimg = new Image;
nonexistentimg.onload = function(){
document.getElementsByTagName('html')[0].className = document.getElementsByTagName('html')[0].className.replace(/\bimg\b/,"");
}
nonexistentimg.src="/nonexistentimg.png";
}
existentimg.src = existingimageurl || (document.images.length?document.images[0].src:'http://www.google.co.uk/images/nav_logo.png');
})();


If your using jQuery (or something similar) and you know there is at least one image on your page...


$(document).ready(function(){
(function(){
var existentimg = new Image;
existentimg.onload = function(){
$('html').addClass('img');
var nonexistentimg = new Image;
nonexistentimg.onload = function(){
$('html').removeClass('img');
}
nonexistentimg.src="/nonexistent.gif";
}
existentimg.src = document.images[0].src;
})();
})

Saturday, 21 February 2009

JavaScript support, who does, who doesn't?

JavaScript or lack of is a thorny issue, but if we take a quick look at some of the user groups that this effects:

1: User agents that don't have JavaScript enabled. As a lot of user tracking software relies on JavaScript to work so it's hard to tell how many users actually don't have JS, but in the beginning of 2009 it could be about 6%. Made up of user-agents that don't support JS, user-agents that have it turned off as part of company policy and user-agents routed though a proxy (e.g. public proxies normally don't support JavaScript)

2: User-agent that you haven't tested your JavaScript on. Just because a user-agent supports JavaScript doesn't mean your script will work (ever done this: if (!document.getElementById){return} ? ), even the four (webkit/moz/opera/ie) main desktop browsers diverge radically in some areas, meaning that there is a good chance that you scripts may not work on anything you haven't tested them on.

3: User-agents where your script is meaningless. e.g. if the user is using a small screen (or zoom software) and they click on a DHTML link that moves some page content from out of view left (eg. margin-left:-9999px) to out of view right (e.g. margin-left:800px;). In these cases JavaScript is no help to the user.

4: Assistive technologies: Most assistive technologies like screen-readers run on the top of your normal browser so although the browser understands JavaScript the assistive technology may not. They may not see things you have written in with JavaScript rendering your JavaScript content inaccessible.

There are probably other user groups effected, will add when they come to mind...

So our user groups fall in to a number of categories...

1. users with browsers that don't support JavaScript at all, or have JavaScript turned off
2. users with browsers can't run your scripts (they error or don't support DOM)
3. users accessing your site though anal proxy, firewall etc...
4. users for whom your JavaScript is redundant (not really any help)
5. users for whom your JavaScript is actively blocking access to content
 

Note: the opinions on this page don't represent that of my employer in anyway. And, actually only vaguely represent my opinions on the date of publication. (Unlike Ms T, I am very much for turning)