29th December 2008

clearing-floats-29dec08To anyone out there reading up on clearing, this is the best method:

http://www.positioniseverything.net/easyclearing.html

It’s totally cross-browser compatible, doesn’t leave any messy markup and leaves the code fully accessible. It does however have 1 flaw…

Scroll down to the part about the IE/Mac problem and you’ll see the fix involves adding a display: inline-block to the container block, which is then re-instated to a display: block in the IE stylesheet.

The problem is that inline-block also affects all the other non-IE browsers. This gives us a wrapper that’s not 100% wide. So what can we do?

Initial Setup

The following example will work on every modern browsing environment except Internet Explorer on Macs. You may just want to leave it like this and not bother accommodating the ancient browser.

MyPage.html

<html>
<head>
   <link rel="stylesheet" type="text/css" href="main.css" media="screen" />
   <!--[if IE]>
      <link rel="stylesheet" type="text/css" href="ie.css" media="screen" />
   <![endif]-->
</head>
<body>
   <div class="clear">
      <div style="float: left;"></div>
      <div style="float: right;"></div>
   </div>
</body>
</html>

main.css

.clear:after {
   content: ".";
   display: block;
   height: 0;
   clear: both;
   visibility: hidden;
}

ie.css

.clear { zoom:1; }

Getting it working in IE/Mac

As described in the P.I.E article, an inline-block trigger on the wrapper will trigger Internet Explorer’s  built in auto-clearing. There are 2 ways to do this:

Overwriting display

Apply 100% width to the inline-block in your main stylesheet This works 99% of the time, just be aware of issues with the IE box model bug.

Add this code to main.css after the clear:after rule:

.clear { display:inline-block; width:100%; }

You now need to revert the display property back to block for IE/Win to get the auto-clearing effect to work. Replace the code in ie.css with:

.clear { zoom:1; display:block; }

Browser sniffers

Have different stylesheets for IE/Win and IE/Mac and include them using a server-side or JavaScript browser sniffer. This is arguably the cleanest fix.

First off remove the conditional include from MyPage.html (<!–[if IE]> …). This file will be included later on using a different method.

Create a new file called iemac.css:

.clear { display:inline-block; width:100%; }

PHP users can them add this code in the html <head> element:

<?php
$browser = strtolower($_SERVER['HTTP_USER_AGENT']);
if (strpos($browser, 'msie')) {
   if (strpos($browser, 'mac')) {
      echo "<link rel='stylesheet' type='text/css' href='iemac.css' />";
   }
   echo "<link rel='stylesheet' type='text/css' href='ie.css' />";
}
?>

Alternatively, you can apply a fix using JavaScript. Again this goes in the <head>:

<script language="javascript" type="text/javascript">
<!--
if (navigator.appName.indexOf("Microsoft Internet Explorer") >= 0) {
   if (navigator.platform.indexOf("Mac") >= 0) {
      document.write("<link rel='stylesheet' type='text/css' href='iemac.css' />");
   }
   document.write("<link rel='stylesheet' type='text/css' href='ie.css' />");
}
// -->
</script>

Tags: , ,

29th December 2008

font-sizes-29dec081A quick note to developers that are styling elements that use monospace fonts (pre, code, q, etc). Be aware that some browsers, like Safari and Chrome, have their own fixed-width font size preference, which by default is set to 13px. This upsets proceedings when you apply a proportional (% or em) font-size to the body.

There are three solutions to counter this problem:

  1. Apply font-size to each element separately
  2. Remove monospace from the font stack and treat it as a variable spaced font
  3. Use a fixed font size

Firefox and Internet Explorer have a single default font size so you can’t apply a larger size to monospace elements.

On the same subject, Google Chrome users can also set different default sizes for their serif and sans-serif fonts. By default these are identical so it will not affect the styling for the majority of users.

Tags: , , , , ,

21st December 2008
Mulled Wine

Mulled Wine

To get into the Christmas spirit – or perhaps as an excuse to get out the Christmas spirits – we are keeping a pan of hot mulled wine on the go leading up to Christmas. Here is our recipe. If you have any variations on this or any tips on how to improve it further (if perfection can be improved) please add your comments.

Ingredients

  • Six cloves
  • Two cinnamon sticks (about 6 inches of stick in total)
  • Quarter of a nutmeg (coursely ground – use a fine grater)
  • Two blades of mace (couple of cm – not too much, can be overpowering)
  • Half a washed lemon, sliced
  • Dried orange peel – I dry some peel out in the summer and keep for this occassion
  • A generous splash of brandy or vodka (this gives the brew an an extra warmth)
  • 5oz Sugar – or a good handful – adjust as required, you can always add more if not sweet enough
  • Fruity wine – two bottles (Beaujolais works well)

Method

Pour a mug of water, and place the dry ingredients and the lemon into a large pan. Heat up and simmer for 20 minutes with a well-fitted lid. You don’t want it steaming out from around the lid, as you lose the spicy aromas. If serving in a jug at the table, you may wish to sieve off the spices at this point, but I leave them in and ladle the mulled wine straight out of the pan.

Add the wine, then heat up gently – but don’t boil it, and there is no need to simmer it any longer – once it is hot, it is ready. Add the brandy (Swiss style) or the Vodka (Swedish style) and you’re ready to go.

This is best enjoyed with an oven-heated mince pie.

Variations would include adding a few allspice berries, star anise, green cardamoms or some dried ginger. Everything is bought in whole and ground as needed. Ready ground nutmeg, cloves etc. lose most of their flavours by the time you get them.

Follow me on Twitter

Tags: , , ,

2nd December 2008

As a part of my integration tasks, I had the following sequence of systems to deal with:

Sequence of systems handling login

Sequence of systems handling login

This is the chain of applications that handle a single-signin for a user. At one end we have the Member Management system, written in ASP Classic, that acts as the main authentication system. For various reasons we had to use that system as the main login system.

Once a user logs in, a HTTP request is sent to the Xaraya CMS, along with user details, and a custom CMS module handles the creation of a new user, or the update of an existing user, and logs that user in.

Further down the line is a Vanilla forum application. When the user logs in or out of Xaraya, an event trigger will then send user details to Vanilla (where the user is created or updated) and then logged in.

Logging out works in just the same way, except a different message is passed down the chain.

The result of a user logging in at one end, is that they will automatically be logged into all the applications in the chain. Given a choice, I would have used something else that all the applications authenticate against, but we were tied to various technical limitations.

One specific action that needed to be carried out, was the passing of cookies down the chain, from one application to another. Each application needed to accept cookies from the browser (where available) and also needed to pass new or updated cookies back to the browser. The browser only interacted with the Member Management System, and so the cookies needed to be passed directly between the applications.

To complicate things more, we have a mix of ASP and PHP, and two separate servers. The servers shared a single domain though, so we were easily able to share the cookies across the servers.

One particular step is the passing of cookies across the ASP system. If we ignore the cookies consumed and generated directly by the MMS, then we have cookies that pass through in both directions.

To handle the flow from left-to-right, the following code is used. First initialise an object to send the HTTP message to the CMS (the message to say “log me in”). We are using SOAP to communicate with the CMS.

  ' XMLHTTP object used to send the outgoing message (to the CMS)
  set xmlhttp = server.CreateObject("MSXML2.ServerXMLHTTP")
  ' Set up the destination and headers; open the connection
  xmlhttp.open "POST", "http://example.com/soap/login", false

Now look through all the cookies that have been sent to *this* page, and pass forward any that are of interest further down the line.

  ' Work through a list of cookies that need to be passed in.
  ' Other cookies (e.g. for forum sessions)
  ' may also be available here and may be useful in logging in and out,
  ' helping to retain sessions across logins.
  ' Loop through all cookies supplied by the browser.
  cookieCount = Request.Cookies.Count
  If cookieCount > 0 Then
    For kk = 1 To Request.Cookies.Count
      cookieName = Request.Cookies.Key(kk)
      cookieValue = Request.Cookies.Item(kk)
      If instr("XARAYASID|lussumocookieone|lussumocookietwo|LussumoUserID|vanillasession",
          cookieName) then
        ' If the cookie is in the list to pass on, then do so.
        xmlhttp.setRequestHeader "Cookie", cookieName & "=" & cookieValue
      End If
    Next
  End If

Finally, after creating the SOAP payload, send the request to log in.

  xmlhttp.setRequestHeader "MessageType", "CALL"
  xmlhttp.setRequestHeader "Content-Type", "text/xml"
  ' Send the message and wait for the response
  xmlhttp.send(SOAPpayloadBody)
  ' wait for response
  ' xmlhttp.waitForResponse(3)
  While xmlhttp.readyState <> 4
    xmlhttp.waitForResponse 200
  Wend

That gets the local browser cookies for this domain, passed on to the CMS. Note we only pass on those cookies that will be of interest, i.e. Xaraya and Vanilla Forum cookies in this case.

Now we need to handle the cookies coming back from he right, as we need to pass them back to the browser. After waiting for the response, it is handled as an XML SOAP message.

  ' Anything other than 200 means error.
  If err.number = 0 And xmlhttp.Status = 200 Then
    ' Collect the data returned.
    Set xmldom = xmlhttp.responseXML
    ' Process the returned data...

Now we are able to look through the cookies that have been returned to us.

    '  We now want to sift through any cookies sent back and pass them on to the
    ' current browser. This means extracting the cookies from the response to the
    ' Xaraya login request, and inserting those same cookies into the current page.

    ' Get the response headers.
    ' This is where we would find the returned cookies.
    strHeaders = xmlhttp.getAllResponseHeaders()
    ' Extract the cookies from the headers
    hArr = split(strHeaders, vbCrLf)
    for kk = 1 to ubound(hArr)
      if instr(hArr(kk), ":") > 0 then
        if left(hArr(kk), instr(hArr(kk), ":")-1) = "Set-Cookie" then
          ' Get the cookie name and value (we will include the path and domain
          ' as part of the 'value').
          ' The name is between the first ':' and the first '='. The value is
          ' everything after the first '='.
          cookieName = trim(mid(hArr(kk), instr(hArr(kk), ":")+1, instr(hArr(kk), "=")-instr(hArr(kk), ":")-1))
          cookieValue = trim(mid(hArr(kk), instr(hArr(kk), "=")+1))

          '  Include the list of cookies that you want to be passed on here.
          if instr("lussumocookieone|lussumocookietwo|LussumoUserID|vanillasession", cookieName) then
            ' Send the cookie on to the current browser (unchanged, i.e. same path and domain)
            Response.AddHeader "Set-Cookie", cookieName & "=" & cookieValue
          end if
        end if
      end if
    next

That’s it. All cookies in that list will be returned to the browser, so if any have been created in the process of logging into the CMS or the Vanilla forums, then they will be passed back and upon visiting those applications the user will find they are logged in.

In a similar way, when the user logs off, sessions are cleared (or flags are set in the sessions to indicate the user has logged off) and some of the cookies are cleared by the user of dates in the past.

I have omitted some of the code for clarity, specifically the declarations of the variables, but the guts of the process is here, and I hope it will prove useful to others. If you need any of this explained or expaned, please ask in the comments section.

Follow me on Twitter

Tags: , , , ,