willoller.com

Avatar

Learning to match the beat of the Old World man.

Ordinal Suffixes in PHP


function ordinalize($int) {

   //sanity
   $int = (int)$int;
   if(!is_numeric($int)) return false;

   // You could internationalize here
   $suffixes = array('th', 'st', 'nd', 'rd');

   // Get the number in the tens place
   $tens = substr($int,-2,1);

   // All of the numbers 10-19 return 'th'
   if($tens == 1) return $int.$suffixes[0];

   // Get the number in the ones place
   $cardinal = substr($int,-1);

   // All numbers ending in 1, 2, 3 have special suffixes
   if($suffixes[$cardinal]) return $int.$suffixes[$cardinal];

   // All remaining numbers end in 'th'
   return $int.$suffixes[0];

}

 

Combining css selectors

We often come across css code in dire need of optimization (details have been changed to protect the guilty), and shows a misunderstanding about the power of css:


h1 {
   font-family: Arial, Helvetica, Geneva, Swiss,  sans-serif;
   font-size: 18px;
   font-style: normal;
   font-weight: bold;
   text-transform: none;
   color: #7D0126;
   margin-bottom: 2px;
   padding-bottom: 0px;
   line-height: 26px;
   margin-top: 12px;
   padding-top: 0px;
}
h2 {
   font-family: Arial, Helvetica, Geneva, Swiss,  sans-serif;
   font-size: 16px;
   font-style: normal;
   font-weight: bold;
   text-transform: none;
   color: #7D0126;
   margin-bottom: 2px;
   padding-bottom: 0px;
   line-height: 24px;
   margin-top: 0px;
   padding-top: 0px;
}
h3 {
   font-family: Arial, Helvetica, Geneva, Swiss,  sans-serif;
   font-size: 14px;
   font-style: italic;
   line-height: 20px;
   font-weight: normal;
   color: #6B917C;
   margin-top: 0px;
   margin-bottom: 7px;
}
h4 {
   font-family: Arial, Helvetica, Geneva, Swiss,  sans-serif;
   font-size: 12px;
   font-style: normal;
   line-height: 18px;
   font-weight: normal;
   padding: 0px;
   margin-top: 0px;
   margin-bottom: 6px;
}
p {
   font-family: Arial, Helvetica, Geneva, Swiss,  sans-serif;
   font-size: 11px;
   font-style: normal;
   line-height: 17px;
   font-weight: normal;
   padding: 0px;
   margin-top: 0px;
   margin-bottom: 6px;
}

/* It keeps going like this but we're going to stop here */

 

As you can see, several properties are repeated across elements.
These can (and should) be consolidated.

Let’s consolidate them first by applying very common properties to the body element:


body {
   font-family: Arial, Helvetica, Geneva, Swiss,  sans-serif;
   font-size: 11px;
   font-style: normal;
   line-height: 15px;
   font-weight: 600;
   font-variant: normal;
   text-transform: none;
   text-decoration: none;
   text-align: left;
   white-space: normal;
   color: #000000;
}
h1 {
   font-size: 18px;
   font-weight: bold;
   color: #7D0126;
   margin-bottom: 2px;
   padding-bottom: 0px;
   line-height: 26px;
   margin-top: 12px;
   padding-top: 0px;
}
h2 {
   font-size: 16px;
   font-weight: bold;
   color: #7D0126;
   margin-bottom: 2px;
   padding-bottom: 0px;
   line-height: 24px;
   margin-top: 0px;
   padding-top: 0px;
}
h3 {
   font-size: 14px;
   font-style: italic;
   line-height: 20px;
   color: #6B917C;
   margin-top: 0px;
   margin-bottom: 7px;
}
h4 {
   font-size: 12px;
   line-height: 18px;
   padding: 0px;
   margin-top: 0px;
   margin-bottom: 6px;
}
p {
   line-height: 17px;
   padding: 0px;
   margin-top: 0px;
   margin-bottom: 11px;
}

 

Okay, now we see a lot of repetion is still happening here. Much of this repetition can be removed by using the comma (,) selector, which allows you to make lists of elements:


body {
   font-family: Arial, Helvetica, Geneva, Swiss,  sans-serif;
   font-size: 11px;
   font-style: normal;
   line-height: 17px;
   font-weight: 600;
   font-variant: normal;
   text-transform: none;
   text-decoration: none;
   text-align: left;
   white-space: normal;
   color: #000000;
}
h1, h2, h3, h4, p {
   margin: 0px;
   padding: 0px;
}
h1, h2 {
   font-size: 16px;
   font-weight: bold;
   color: #7D0126;
   margin-bottom: 2px;
   line-height: 16px;
   line-height: 24px;
}
h1 {
   font-size: 18px;
   line-height: 26px;
   margin-top: 12px;
}
h3 {
   font-size: 14px;
   font-style: italic;
   line-height: 20px;
   color: #6B917C;
   margin-bottom: 7px;
}
h4 {
   font-size: 12px;
   line-height: 18px;
   margin-bottom: 6px;
}
p {
   margin-bottom: 6px;
}

 

There is a pattern to the font-size, margin-height, and line-heights. We will now use this to our advantage to make life even easier.


body {
   font-family: Arial, Helvetica, Geneva, Swiss,  sans-serif;
   font-size: 11px;
   font-style: normal;
   font-weight: 600;
   font-variant: normal;
   text-transform: none;
   text-decoration: none;
   text-align: left;
   white-space: normal;
   color: #000000;
}
h1, h2, h3, h4, p {
   margin: 0px;
   padding: 0px;
   line-height: 150%;  /* A good approximation */
   margin-bottom: 0.5em /* another approximation */
}
h1, h2 {
   font-size: 16px;
   font-weight: bold;
   color: #7D0126;
   margin-bottom: 2px;
}
h1 {
   font-size: 18px;
   margin-top: 12px;
}
h3 {
   font-size: 14px;
   font-style: italic;
   color: #6B917C;
   margin-bottom: 7px;
}
h4 { font-size: 12px; }

 

With just a few basic css selectors, this code was cut in half.

Textile ol li count bug

Just hit a bug with the Textile 2.0 library:


# Portland, OR
# Sanford, FL
# Albuquerque, NM
# San Diego, CA
# Bellingham, WA
 

Was producing:


<ol>
   <li>Portland, OR</li>
   <li>Sanford, FL</li>
   <li>Albuquerque, NM</li>
   <li>San Diego, CA   </li>
</ol>
<ol>
   <li>Bellingham, WA</li>
</ol>
 

Found the solution here:

You can work around the problem, by replacing these two lines (in the fList function in /textpattern/lib/classTextile.php):

foreach($text as $line) {
  $nextline = next($text);

 
with:

foreach($text as $nr => $line) {
  $nextline = isset($text[$nr+1]) ? $text[$nr+1] : false;

 

“Cascading” in CSS

The “cascading” in “Cascading Style Sheets” has several facets: computed values, inheritance, and specificity. Understanding how these cascades work is an integral part of your css ninja training.

Computed Values

Many of the values assigned have a unit. Some of these are relative (like em and <span>), and some are absolute (like px and in). Relative values are based on their parents: an element with a width of 50 uses the element’s parent to determine the actual width of the element.

width: 50%
width: 50%

Likewise, if both the parent and child elements’ font-sizes are 1.5em, the child’s actual font size will be larger than the parent’s.

1.5em 1.5em 1.5em

Absolute values do not change based on their parent values. These are often obvious: color: red; for example. Pixel values are absolute, though the actual value displayed by the UA(User Agent) may differ (due to display or text-size settings).

Inheritance

Inheritance is the passing on of attributes from parents to children. It works in CSS like this: An element’s font color is set to red. The color for its child elements will also be red (if left unspecified or set to inherit).

color: red
no color specified
color: inherit

Specificity

This is how CSS decides between competing styles. Take a look at the following code:


p#special_error { color: red; }
.error {         color: orange; }
p {              color: black; }

 

<p>no class or id</p>
<p id="special_error" class="error">class and id</p>
<p class="error">p class</p>
<div class="error">div class</div>
<div id="special_error">div id</div>
 

So what color do the elements end up with? To answer that question, we need to know how the competing selectors are chosen.

Each selector has a particular weight outlined in this table:

selectorweightexample
id100#special_error
class10.error
element1p

These weights are all added up and the “heaviest” selector set wins. So using the css above, here are the results:


<p>no class or id</p><!-- #000000 -->
<p id="special_error" class="error">class and id</p><!-- red -->
<p class="error">p class</p><!-- orange -->
<div class="error">div class</div><!-- orange -->
<div id="special_error">div id</div><!-- inherits -->
 

Links

w3.org
wikipedia
htmlhelp

Counting Characters php vs javascript

On a recent project, an issue cropped up where we were exporting xml reports to a third party, who had rules about line lengths in Description fields.

So, I wrote up a quick-and-dirty character counter for the description field so the client can keep their descriptions under the 1500-word limit.

Here’s how it was done:


if (!$fdata['description']) {
   $errors[] = "You must enter a Description";
} elseif(strlen($fdata['description']) > 1500) {
   $len = strlen($fdata['description']);
   $errors[] = "Descriptions are limited to 1500 characters ($len)";
}

 

Now the html and javascript:


<li class="description">
   <label for="htmlarea" class="required">Description *</label>
   <textarea name="description" id="htmlarea" cols="80" rows="20" class="textarea">< ?= $ff['description'] ?></textarea>
   <p class="hint" id="desc_char_count">1500 character limit</p>
</li>
 

$(function(){
   $('#htmlarea').keyup(function(){
      var charLength = $(this).val().length;
      $('#desc_char_count').html(charLength + ' of 1500 characters used');
      if($(this).val().length > 1500) {
         $('#desc_char_count').removeClass('positive').addClass('negative').html('<strong>You have ' + $(this).val().length + ' characters. You may only have up to 1500 characters.</strong>');
      } else {
         $('#desc_char_count').addClass('positive').removeClass('negative');
      }
   });
   $('#htmlarea').keyup();
});

 

All was working well, except I underestimated the descriptions. The next morning, the thing was broken. The php side was kicking validation errors (“over 1500 characters”), while the javascript was counting a mere 1480. Why?

Turns out the data was full of bullets and other multibyte characters. To make the counts match, I needed multibyte-safe php:


if (!$fdata['description']) {
   $errors[] = "You must enter a Description";
} elseif(mb_strlen($fdata['description'],'UTF-8') > 1500) {
   $len = mb_strlen($fdata['description'],'UTF-8');
   $errors[] = "Descriptions are limited to 1500 characters ($len)";
}

 

Hooray! Now the counts match!

Use Firebug to Update A Huge Form

Had a problem recently where I had to update hundreds of input fields within a shopping cart, setting prices of product variants from $200 to $49.

They were named in sequence:


...
<input name="vs[1667][price]" value="200" />
<input name="vs[1668][price]" value="200" />
<input name="vs[1669][price]" value="200" />
...

 

So I busted out the command line in Firebug.


for (var i=0; i&lt;10000; i++) {
   if(document.productvariantsform.elements["vs[" + i + "][price]"].value) {
      document.productvariantsform.elements["vs[" + i + "][price]"].value = "49.00";
   }
}

 
but all I got were “has no properties” errors.

I got in touch with my local Javascript guru who helped me come up with some code that did work:


var frm = document.productvariantsform;
for (var i=0; i < frm.elements.length; i++) {
   if ((frm.elements[i].name.match(/\[price\]$/)) && (frm.elements[i].value)) {
      frm.elements[i].value = "49.00";
   }
}

 

This saved literally hours of [TAB][TAB][TAB][TAB][Ctrl+V].
Thank you Firebug!

Textile – Humane Text Generator

Blogs, bulletin boards, community sites—the whole web2.0© rely on the same thing: user input. On the web, user input usually means HTML.

Some simple HTML is easy to learn, like <b>bold</b> and <i>italics</i>, but other techniques (like links, lists, and blockquotes) can be a little more daunting. For a site owner, badly written HTML can break a site.

So what are you, the site owner, to do? You shouldn’t have to learn all about HTML yourself (unless you want to), and can’t force your readers to learn HTML just to post feedback.

There are a few apps that can help people “mark up” text, and these work well, in general. The drawbacks are they can be bulky or hard to use, and suffer from technical issues including lack of browser support and buggy performance. These drawbacks make them more suited for intranets and administrators, and less suited for the rest of the World-Wide Web.

Lately, another method has resurfaced: server-side markup generators. They work behind the scenes to change easier markup into HTML. Anyone familiar with bulletin boards will know about BBCode; it generally worked like this:

[b]Bold[/b], [i]italics[/i], [u]underlined[/u]. will produce bold, italics, underlined.

But this is not really enough. Its really just HTML with replaced with [ and ]. BBCode also can’t do some of the the advanced things (lists, blockquotes) HTML still has to offer.

Along came Textile

Here at Black Dog, we use Textile to solve this problem. It is a server-side markup generator, like BBCode, but it has all of the bells and whistles you need to produce good HTML. Instead of using HTML-like syntax, it uses easy-to-remember symbols. The best part is, the symbols make sense before they are turned into HTML.

<strong>bold</strong>, <em>italics</em>. becomes bold, italics.

Textile also handles lists and sublists, ordered and unordered:


* An item in an unordered list
* Another unordered list item
** Second Level item
** Second Level item
*** Third Level

# An item in a numbered (ordered) list
# Another item
## Second level item
 

It also helps you out with the little things: double quotes and single quotes are made “curly,” and dashes—I love those helpful little guys—are made into their correct typographical charaters.

The best part: Textile doesn’t ruin good HTML, so you can mix-and-match HTML and Textile if you want to, but it quietly throws out bad or broken HTML so your content stays nice, clean, and readable.

Everybody wins

As a site owner, you have some additional protection against buggy HTML from users or even yourself. As a user, you can make make your text stand out without learning a bunch of HTML tags. As a reader, the web will be a little easier on the eyes.

Further Information

Textile’s entry on Wikipedia
Advanced Textile reference (hobix.com)
Textpattern (CMS built with Textile)
Dean Allen’s home page (Creator of Textile and Textpattern)

Typography on the Web

Typography on the web resembles print typography only superficially. There are important limitations with units, fonts, styles, and effects.

In web design, there are a few common units used for setting the sizes of elements. They are:

percentage
em em is a multiplier applied to the current font size: 1em is equal to the current font size, and 2em means 2 times the current font size.
pt points, 1 pt is the same as 1/72 inch
px pixels, a dot on the computer screen

For a full list, see W3Schools.

The rub is that all of these units are converted into pixels for display on the screen. Each OS and browser use a slightly different algorithm for this conversion; generally 9pt=12px but that will vary depending on the settings of the individual computer.

These differences are relatively minor (1 or 2 pixels) when applied to text alone, but can become unbearable when specifying line height, letter spacing, word spacing, etc. When displayed on-screen, extra care must be taken to consider these uncontrollable discrepancies in font rendering algorithms.

Therefore, the following css units are generally used by Black Dog Studios for setting font sizes on fixed-width layouts:

font-size: px
line-height:
letter-spacing: em
word-spacing: em
margins: px (sometimes em)
padding: px (rarely em)

We of course do our best to match design comps which use points or an unknown unit; however Black Dog Studios cannot guarantee pixel-perfect (or sub-pixel-perfect) accuracy when making these conversions.

The following links are to articles and tools related to the conversion between px, pt, em, and %.

Continue

Before you go