<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:blogger='http://schemas.google.com/blogger/2008' xmlns:georss='http://www.georss.org/georss' xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-4070763839197449611</id><updated>2024-09-11T19:38:21.029-07:00</updated><category term="Perl subroutine"/><title type='text'>MobileSiteOS</title><subtitle type='html'>MobileSiteOS is my blog about all things related to the design and development of mobile websites. My particular interests are in the use of open source software solutions for the mobile web. I also place a high emphasis on providing multi-access solutions vs. single access (only for iphone, etc.) website creation.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://mobilesiteos.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4070763839197449611/posts/default?redirect=false'/><link rel='alternate' type='text/html' href='http://mobilesiteos.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Dwight</name><uri>http://www.blogger.com/profile/10490400264168860529</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>5</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-4070763839197449611.post-7669967564631253403</id><published>2010-02-02T21:05:00.000-08:00</published><updated>2010-02-02T21:05:56.214-08:00</updated><title type='text'>WURFL to Perl Data Script</title><content type='html'>&lt;b&gt;WURFL to Perl&lt;/b&gt; data is an alternative method of implementing the WURFL XML Mobile Device Data file for smaller web projects that I have been working on for a while. Instead of parsing the complete WURFL XML file or loading the data to a database platform like MySQL, WURFL to Perl is an adaptation of the WURFL Data written as Perl code. That is, we use the WURFL Device Data as converted to Perl hashes and a configuration file.&lt;br /&gt;
&lt;br /&gt;
This discussion assumes you have some familiarity with WURFL XML Device Detection Data. If not, please see &lt;a href=&quot;http://wurfl.sourceforge.net/&quot;&gt;http://wurfl.sourceforge.net/&lt;/a&gt;&amp;nbsp;for references and downloads of the actual WURFL XML data. Usage and adaptation is of coarse heavily dependent on your ability to do Perl programming too.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Let&#39;s Get Small&lt;/b&gt;&lt;br /&gt;
&lt;b&gt;&lt;br /&gt;
&lt;/b&gt;&lt;br /&gt;
The first step is to condense WURFL Data down to just what we need for our particular project. WURLF Data is arguably the best and most complete reference for mobile device capabilities and as such, is a very large XML file. Large projects may need to have all device information readily available, but many times a project just needs certain device capabilities exposed. Below is a snippet from our configuration file which shows several configuration settings.&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;# Our configuration variables...
$config_vars = {

  wurfl_path =&amp;gt; &#39;./lib/WURFL/&#39;,
  wurfl_file =&amp;gt; &#39;./lib/WURFL/wurfl.xml&#39;,
  wurfl_status =&amp;gt; &quot;WURFL Status: OK!\n&quot;,
  wurfl_select =&amp;gt; [
    &#39;ajax&#39;, &#39;bearer&#39;, &#39;cache&#39;, &#39;css&#39;, &#39;display&#39;, &#39;image_format&#39;, &#39;markup&#39;, &#39;rss&#39;, &#39;transcoding&#39;, &#39;xhtml_ui&#39;
  ],                          # WURFL groups to include
  wurfl_min_width =&amp;gt; 169,  # Minimum resolution width to accept (&amp;gt;=)
  wurfl_min_xhtml =&amp;gt; 1,    # Minimum xhtml markup level to accept (&amp;gt;=)
  wurfl_dump_indent =&amp;gt; 0   # Sets &#39;Data::Dumper&#39; indentation level, (0 is none)

}&lt;/pre&gt;&lt;pre&gt;&lt;/pre&gt;&lt;br /&gt;
The &#39;wurfl_select&#39; hash key is probably the most important, as it specifies which WURFL &#39;group&#39; data types will be included in the final WURFL to Perl code. I added &#39;wurfl_min_width&#39; and &#39;wurfl_min_xhtml&#39; as they were settings which were of interest in my projects. Others can be added here as applicable. The advantage is that data not required will be filtered away, making the Perl code smaller.&lt;br /&gt;
&lt;br /&gt;
The configuration file also includes code for &#39;encoding&#39; common string segments of &#39;user agent&#39; text into abbreviated ones. Here is a sample:&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;# Sub to encode common long string segments in user agents
sub user_agent {

    # Input a user agent string
    my $ua = shift;
    
    # Remove non word characters
    $ua =~ s/_//g;
    $ua =~ s/\W+//g;

    # Encode many common long strings
    $ua =~ s/^3GSonyEricsson/3gse_/;
    $ua =~ s/^SonyEricsson/snye_/;
    $ua =~ s/^ACSNF30NE/ac31_/;
    $ua =~ s/^AUDIOVOX/audx_/;
    $ua =~ s/^Alcatel/alcl_/;
    $ua =~ s/^BlackBerry/blck_/;
    $ua =~ s/^Compal/cpl_/;
    $ua =~ s/^DoCoMo/dcm_/;
    ....
    ...
    ..
    .&lt;/pre&gt;&lt;br /&gt;
We also encode device capabilites for brevity:&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;# Hash of abbreviations for WURFL standard capabilities
$abbrev_names = {

    &#39;ajax&#39; =&amp;gt; {
        &#39;ajax_manipulate_css&#39; =&amp;gt;  &#39;css&#39;,
        &#39;ajax_manipulate_dom&#39; =&amp;gt;  &#39;dom&#39;,
        &#39;ajax_support_getelementbyid&#39; =&amp;gt; &#39;byid&#39;,
        &#39;ajax_support_inner_html&#39; =&amp;gt;  &#39;inner&#39;,
        &#39;ajax_support_javascript&#39; =&amp;gt;  &#39;js&#39;,
 &#39;ajax_support_events&#39; =&amp;gt;  &#39;events&#39;,
 &#39;ajax_support_event_listener&#39; =&amp;gt; &#39;listen&#39;,
        &#39;ajax_xhr_type&#39; =&amp;gt;   &#39;xhr&#39;
    },

    &#39;bearer&#39; =&amp;gt; {
 &#39;max_data_rate&#39; =&amp;gt;  &#39;rate&#39;
    },
    ....
    ...
    ..
    .&lt;/pre&gt;&lt;pre&gt;&lt;/pre&gt;&lt;pre&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Times New Roman&#39;; white-space: normal;&quot;&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Times New Roman&#39;; white-space: normal;&quot;&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Times New Roman&#39;; white-space: normal;&quot;&gt;The configuration file is important because we use it to define and then access our WURFL to Perl data code. My &#39;perl_wurfl.cgi&#39; script is used to create your version of WURFL to Perl code, base on your configuration settings. The &#39;perl_wurfl.cgi&#39; script will massage and manipulate the latest WURFL XML Data file used, encoding common strings, filtering and condensing it down. The included finished WURFL to Perl code example files (from our download) show a reduction of approximately 10:1.&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Times New Roman&#39;; white-space: normal;&quot;&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Times New Roman&#39;; white-space: normal;&quot;&gt;&lt;b&gt;See is Believing&lt;/b&gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Times New Roman&#39;; white-space: normal;&quot;&gt;&lt;b&gt;
&lt;/b&gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Times New Roman&#39;; white-space: normal;&quot;&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Times New Roman&#39;; white-space: normal;&quot;&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Times New Roman&#39;; white-space: normal;&quot;&gt;There is a lot going on here and the best way to see it is to install and run the &#39;perl_wurfl.cgi&#39; script. Watch as it steps through each part of the process and you will get a feel for how it works and how much it is doing.&amp;nbsp;Please note: the &#39;perl_wurfl.cgi&#39; script will be very slow at first because of the 14+Mb size of the WURFL XML data file. So be patient while it is runnning. It also likes lots of memory ;)&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Times New Roman&#39;; white-space: normal;&quot;&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Times New Roman&#39;; white-space: normal;&quot;&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Times New Roman&#39;; white-space: normal;&quot;&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Times New Roman&#39;; white-space: normal;&quot;&gt;The &#39;perl_wurfl.cgi&#39; script does some fancy Perl comparisons and produces shortened &#39;unique&#39; encoded user agent based hash keys. This is the reason your application will need to use the same configuration file as the&amp;nbsp;&#39;perl_wurfl.cgi&#39; script. From these Perl hash keys, we seek a &#39;best match&#39; to the incoming user agent of the website visitor. This all works reasonably well because we use a combination of brute force searches (Regex) and textual data comparison.&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Times New Roman&#39;; white-space: normal;&quot;&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Times New Roman&#39;; white-space: normal;&quot;&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Times New Roman&#39;; white-space: normal;&quot;&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Times New Roman&#39;; white-space: normal;&quot;&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Times New Roman&#39;; white-space: normal;&quot;&gt;From this point on, our process works much the same as other WURFL applications. We roll up the capabilities by combining each successive &#39;fall back&#39; user agent (device id in WURFL terms) and provide a best guess of it&#39;s current browser capabilities in Perl hash form. The difference is, we use&amp;nbsp;textual data comparison in the final device detection stage &amp;nbsp;instead of simple user agent string matching.&amp;nbsp;This provides better &#39;new device&#39; detection for new user agents that haven&#39;t been incorporated into the WURFL data yet.&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Times New Roman&#39;; white-space: normal;&quot;&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Times New Roman&#39;; white-space: normal;&quot;&gt;&lt;pre style=&quot;margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;&quot;&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Times New Roman&#39;; white-space: normal;&quot;&gt;&lt;b&gt;Give it a Try&lt;/b&gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style=&quot;margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;&quot;&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Times New Roman&#39;; white-space: normal;&quot;&gt;&lt;b&gt;
&lt;/b&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Times New Roman&#39;; white-space: normal;&quot;&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Times New Roman&#39;; white-space: normal;&quot;&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Times New Roman&#39;; white-space: normal;&quot;&gt;Also included in my download is the &#39;site_wurfl.cgi&#39; script. This is actually the more important of the two. My &#39;site_wurfl.cgi&#39; script demo&#39;s our WURFL to Perl data capabilities, while giving a realistic example of how it might be integrated into other Perl scripts. The &#39;perl_wurfl.cgi&#39; script is only run when you download and update to the latest WURFL XML Data file. Thus &#39;perl_wurfl.cgi&#39; is just a &#39;helper&#39; script and should not be given any website user access of any kind. I update locally (yes my 4+ year old Toshiba laptop runs it just fine), which is the safest way to go.&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Times New Roman&#39;; white-space: normal;&quot;&gt;&lt;b&gt;
&lt;/b&gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Times New Roman&#39;; white-space: normal;&quot;&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Times New Roman&#39;; white-space: normal;&quot;&gt;Use the included &#39;site_wurfl.cgi&#39; script as a guide to how we access our WURFL to Perl code. It is also a quick and convenient way to test configuration changes or new devices against current WURFL to Perl code. Or just use a &#39;User Agent Switcher&#39; in your favorite browser and watch the process at work.&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Times New Roman&#39;; white-space: normal;&quot;&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Times New Roman&#39;; white-space: normal;&quot;&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Times New Roman&#39;; white-space: normal;&quot;&gt;&lt;b&gt;For more info, please see:&lt;/b&gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Times New Roman&#39;; white-space: normal;&quot;&gt;&lt;b&gt;
&lt;/b&gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Times New Roman&#39;; white-space: normal;&quot;&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Times New Roman&#39;; white-space: normal;&quot;&gt;Demo the &#39;site_wurfl.cgi&#39; script:&amp;nbsp;&lt;a href=&quot;http://opensite.mobi/cgi-bin/site_wurfl.cgi&quot;&gt;Site-WURFL&lt;/a&gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;/pre&gt;&lt;pre&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Times New Roman&#39;; white-space: normal;&quot;&gt;Download Site-WURFL w/ WURFL-Perl code:&amp;nbsp;&lt;a href=&quot;http://code.google.com/p/mobilesiteos/&quot;&gt;http://code.google.com/p/mobilesiteos/&lt;/a&gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;/pre&gt;&lt;pre&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Times New Roman&#39;; white-space: normal;&quot;&gt;See WURFL to Perl in action on our website:&amp;nbsp;&lt;a href=&quot;http://opensite.mobi/index.html?debug=test_wurfl&quot;&gt;OpenSiteMobile&lt;/a&gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Times New Roman&#39;; white-space: normal;&quot;&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Times New Roman&#39;; white-space: normal;&quot;&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Times New Roman&#39;; white-space: normal;&quot;&gt;
&lt;/span&gt;&lt;/pre&gt;</content><link rel='replies' type='application/atom+xml' href='http://mobilesiteos.blogspot.com/feeds/7669967564631253403/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://mobilesiteos.blogspot.com/2010/02/wurfl-to-perl-data-script.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4070763839197449611/posts/default/7669967564631253403'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4070763839197449611/posts/default/7669967564631253403'/><link rel='alternate' type='text/html' href='http://mobilesiteos.blogspot.com/2010/02/wurfl-to-perl-data-script.html' title='WURFL to Perl Data Script'/><author><name>Dwight</name><uri>http://www.blogger.com/profile/10490400264168860529</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4070763839197449611.post-1811929900014937241</id><published>2009-12-07T11:26:00.000-08:00</published><updated>2009-12-07T11:45:29.556-08:00</updated><title type='text'>How to Get Character Widths for a Browser&#39;s Font Size</title><content type='html'>A few days back, I blogged about &quot;&lt;a href=&quot;http://mobilesiteos.blogspot.com/2009/12/how-to-force-wrap-of-long-strings-for.html&quot;&gt;how to force string wrapping&lt;/a&gt;&quot; for mobile device display. In order to know when to break a string of text, we would like to know how many characters of text fit into any given html element on the page. Simple right? If you know an element&#39;s width, as I usually do since I use a fixed width &#39;body&#39; div element and can make a reasonable guess as to what each child elements width will be, all I need is the width of each character. That way, I can find the number of characters per line for that particular element and break accordingly.&lt;br /&gt;
&lt;br /&gt;
So how do you find the width of each character? Now we have a problem. There is no way to know before a page is rendered what the width of a character is for a given font, font size, font style, etc. in a given user&#39;s browser. Remember, we just specify what font and font size to we want them to use. The browser can and will use whatever font and font size it deems appropriate. This is especially true for mobile devices, which vary greatly in screen size, available fonts, available font size and browser software.&lt;br /&gt;
&lt;br /&gt;
That said, in many of my scripts I use a set character width vs font size relationship hash:&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;my %character_width = (
 &#39;font_large&#39; =&amp;gt; 13,
 &#39;font_medium&#39; =&amp;gt; 10,
 &#39;font_small&#39; =&amp;gt; 8,
 &#39;font_x_small&#39; =&amp;gt; 6,
 &#39;font_xx_small&#39;=&amp;gt; 5,
);
&lt;/pre&gt;&lt;br /&gt;
...where &#39;font_large&#39; is the character width in pixels for a style specification of font-size:large, &#39;font_x_small&#39; is for font-size:x-small, etc. This actually works reasonably well in many cases. Sometimes your text will push outside it&#39;s container element, but on average it looks ok.&lt;br /&gt;
&lt;br /&gt;
But if you want a more accurate measure of character width for each user, you can try this technique. What we do is render a page and let JavaScript tell us what character width is being used for each font size. Here is the html we use in the polling page:&lt;br /&gt;
&lt;pre&gt;....
&amp;lt;div&amp;gt;
&amp;lt;span id=&quot;xl&quot; style=&quot;font-size: x-large;&quot;&amp;gt;Open Source&amp;lt;/span&amp;gt;
    &amp;lt;span id=&quot;lg&quot; style=&quot;font-size: large;&quot;&amp;gt;Open Source&amp;lt;/span&amp;gt;
    &amp;lt;span id=&quot;md&quot; style=&quot;font-size: medium;&quot;&amp;gt;Open Source&amp;lt;/span&amp;gt;
    &amp;lt;span id=&quot;sm&quot; style=&quot;font-size: small;&quot;&amp;gt;Open Source&amp;lt;/span&amp;gt;
    &amp;lt;span id=&quot;xs&quot; style=&quot;font-size: x-small;&quot;&amp;gt;Open Source&amp;lt;/span&amp;gt;
    &amp;lt;span id=&quot;xx&quot; style=&quot;font-size: xx-small;&quot;&amp;gt;Open Source&amp;lt;/span&amp;gt;
&amp;lt;/div&amp;gt;
....

&lt;/pre&gt;Pretty basic. The surrounding div is usually set to&amp;nbsp;&lt;span style=&quot;font-family: monospace; white-space: pre;&quot;&gt;style=&#39;visibility:hidden;&#39;, &lt;span style=&quot;font-family: &#39;Times New Roman&#39;; white-space: normal;&quot;&gt;but I left it visible here for demo purposes. As you can see, just a simple line of text&amp;nbsp;of known character length (11 characters in &#39;Open Source&#39;) for each font size span tag.&amp;nbsp;And here is the JavaScript which sends character width information to your script:&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;pre&gt;....&lt;/pre&gt;&lt;pre&gt;&lt;/pre&gt;&lt;pre&gt;function init_page(){
  var size_output = &#39;&#39;;
  var site_url = &#39;http://your.website.com/cgi-bin/your_script.cgi?&#39;;
  var width_array = [ &#39;xl&#39;, &#39;lg&#39;, &#39;md&#39;, &#39;sm&#39;, &#39;xs&#39;, &#39;xx&#39; ];
    
  &lt;span style=&quot;font-family: &#39;Times New Roman&#39;; white-space: normal;&quot;&gt;&lt;span style=&quot;font-family: monospace;&quot;&gt;&lt;span style=&quot;white-space: pre;&quot;&gt;for(var i=0; i&amp;lt;width_array.length; i++) {
    size_output += &#39;&amp;amp;&#39; + width_array[i]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span style=&quot;font-family: &#39;Times New Roman&#39;; white-space: normal;&quot;&gt;&lt;span style=&quot;font-family: monospace;&quot;&gt;&lt;span style=&quot;white-space: pre;&quot;&gt;      + &#39;=&#39; + get_character_width(width_array[i]);
  }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;size_output = size_output.substring(1);

  // Send info to your script...
  window.location = site_url + size_output;
}

// Helper functions...
 
function get_character_width(el_id) {
    var output = 0;
    var element = document.getElementById(el_id);
    var text = element.innerHTML;

    if (typeof element.clip !== &quot;undefined&quot;) {
       output = element.clip.width || 0;
    } else {
        if (element.style.pixelWidth) {
            output = element.style.pixelWidth || 0;
        } else {
            output = element.offsetWidth || 0;
          }
      }
    output = round_up_down(output/text.length, 0);
    
    if (output &amp;lt; 5) output = 5;   // practical limit is 5px per character
    return output;
}

function round_up_down(number, num_of_dec_places) {
    var num_to_10th_pow = parseInt(Math.pow(10, num_of_dec_places));
    return number = Math.round(number * num_to_10th_pow) / num_to_10th_pow;
}
....&lt;/pre&gt;Use the above in a &#39;polling&#39; (index.html) page which loads the above JavaScript at page load. I use the Dojo Tookit, so I left that stuff out, but a simple &amp;lt;body onload=&quot;init_page();&quot;&amp;gt; will work just fine. So the above JavaScript gets the overall size of each span of text, which has been set to each specific font size, divides it by the number of characters and voila, we have the character size in pixels. Cool eh? I just add this new info to my redirect uri string and it is sent to my script.&lt;br /&gt;
&lt;br /&gt;
Now you might still be asking why this is important. Well as mobile sites become more advanced, there will be more info displayed from general databases and such. Since this data might not already be conditioned for mobile display, the above technique, among others, may become the norm and not the exception.&lt;br /&gt;
&lt;br /&gt;
Here is an example of it in action. Go to my website:&amp;nbsp;&lt;a href=&quot;http://opensite.mobi/&quot;&gt;http://opensite.mobi&lt;/a&gt;.&amp;nbsp;Watch as it first goes to our index.html page. Quickly it redirects to our site. Now look at the redirect uri in your browser&#39;s navigation line. I send the info bundled (I write a cookie to store this), but you will see something like &#39;rev_cookie=unknown:js_yes:14:10:9:8:6:6&#39; if JavaScript was enabled. The numbers part is what we are interested here. Largest to smallest, we now have the character sizes as gathered for this browser. Note: on my website, once a cookie is written the index.html page skips the character size stuff, so you will have to clear cache to see it again if you try multiple times.&lt;br /&gt;
&lt;br /&gt;
If you know of similar or other data preparation techniques for mobile display, please post a comment with code or a url. I searched a good bit some time ago, but you never always know what&#39;s really out there.</content><link rel='replies' type='application/atom+xml' href='http://mobilesiteos.blogspot.com/feeds/1811929900014937241/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://mobilesiteos.blogspot.com/2009/12/how-to-get-character-widths-for.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4070763839197449611/posts/default/1811929900014937241'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4070763839197449611/posts/default/1811929900014937241'/><link rel='alternate' type='text/html' href='http://mobilesiteos.blogspot.com/2009/12/how-to-get-character-widths-for.html' title='How to Get Character Widths for a Browser&#39;s Font Size'/><author><name>Dwight</name><uri>http://www.blogger.com/profile/10490400264168860529</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4070763839197449611.post-3620947274577238286</id><published>2009-12-03T07:36:00.000-08:00</published><updated>2009-12-03T07:42:53.944-08:00</updated><title type='text'>Click here for Mobile Website Development</title><content type='html'>I&#39;ve been surfing the web for a long time, looking for articles on mobile web development and design. Tons of articles, some good - some just the same old rehash.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Anyway, I came across this url today and it is the best reference to good quality mobile development articles I have seen yet. Have a look if your are new to the game:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href=&quot;http://komunitasweb.com/2009/03/29-tutorials-to-help-you-build-your-mobile-site/&quot;&gt;http://komunitasweb.com/2009/03/29-tutorials-to-help-you-build-your-mobile-site/&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;One stop shopping on the web...&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mobilesiteos.blogspot.com/feeds/3620947274577238286/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://mobilesiteos.blogspot.com/2009/12/click-here-for-mobile-website.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4070763839197449611/posts/default/3620947274577238286'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4070763839197449611/posts/default/3620947274577238286'/><link rel='alternate' type='text/html' href='http://mobilesiteos.blogspot.com/2009/12/click-here-for-mobile-website.html' title='Click here for Mobile Website Development'/><author><name>Dwight</name><uri>http://www.blogger.com/profile/10490400264168860529</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4070763839197449611.post-725979884448189303</id><published>2009-12-01T14:29:00.000-08:00</published><updated>2009-12-01T16:19:47.856-08:00</updated><title type='text'>How to force wrap of long strings for mobile display</title><content type='html'>One problem I came across a while back while developing scripts that generate pages to be viewed by mobile devices was that long continuous strings of characters would not wrap &#39;correctly&#39; (at all). This was made more noticable since I tend to use width defined html tags. For example, url&#39;s you want to show directly in html may often be wider than the screen that will be viewing them. Now you might say, so what. They just extend past the current viewing window. With mobile devices, this is not an optimum situation for efficient browsing.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;When designing a mobile site, it is best not to make the user scroll any more than they have to. And not making the user scroll horizontally is even more important. I believe some browsers don&#39;t even allow it, (newer mobile browsers are more capable). And this problem actually happens quite often when you output url or file path strings from within your scripts. Especially when outputing strings for debugging or error reporting.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So what to do?&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Well, I wrote some Perl code to force breaks in long strings of characters or in certain long words within paragraphs of text which wouldn&#39;t wrap to my liking.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Here is the code:&lt;/div&gt;&lt;pre&gt;&lt;br /&gt;sub clean_breaks {&lt;br /&gt;# -----------------------------&lt;br /&gt;&lt;br /&gt;my $string = shift;&lt;br /&gt;my $cl_break = shift;&lt;br /&gt;my $filter = shift || &#39;\W&#39;;&lt;br /&gt;my $line = 0;&lt;br /&gt;my $word = &#39;&#39;;&lt;br /&gt;my @words = ();&lt;br /&gt;&lt;br /&gt;@words = split / /, $string;&lt;br /&gt;&lt;br /&gt;foreach $word (@words) {&lt;br /&gt;&lt;br /&gt;  my $more_word = &#39;&#39;;&lt;br /&gt;  my @more_words = ();&lt;br /&gt;&lt;br /&gt;  if(length $word &amp;gt; $cl_break) {&lt;br /&gt;&lt;br /&gt;$word =~ s/(.{$cl_break})/$1 /g;&lt;br /&gt;@more_words = split / /, $word;&lt;br /&gt;foreach $more_word (@more_words) {&lt;br /&gt;&lt;br /&gt;    if(length $more_word &amp;gt; ($cl_break/2)) {&lt;br /&gt;&lt;br /&gt; $more_word = reverse $more_word;&lt;br /&gt; $more_word =~ s/($filter)/$1&amp;gt;\/ rb&amp;lt;/;&lt;br /&gt; $more_word = reverse $more_word;&lt;br /&gt; unless ($more_word =~ m/&amp;lt;br&amp;gt;|&amp;lt;br \/&amp;gt;/) {&lt;br /&gt;                   $more_word =~ s/^(.{$cl_break})/$1&amp;lt;br \/&amp;gt;/;&lt;br /&gt;              }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;$word = join (&#39;&#39;, @more_words);&lt;br /&gt;$line = 0;&lt;br /&gt;&lt;br /&gt;  } else {&lt;br /&gt;&lt;br /&gt;$line += length $word;&lt;br /&gt;if ($line &amp;gt; $cl_break ) { $word = &#39;&amp;lt;br /&amp;gt;&#39; . $word;  $line = 0; }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;join (&#39; &#39;, @words);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;It works by breaking up long strings of text, base on the screen width of the user&#39;s display, times the html tag&#39;s % of screen width for that paticular tag (ie: 100%,  or 1 for the body tag), divided by the width of each character. I work in pixels, but the units aren&#39;t important when the principle is respected.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So what you want is the approximate number of characters per line where normal wraping occurs, for that particular tag. And yes, the user&#39;s screen width and character width values will have to be guessed since they will vary by the user&#39;s browser, device and user settings. More on that another day.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So, you enter a string of text (or a string of continuous characters) as the first input to the subroutine &#39;&amp;amp;clean_breaks&#39; and then a &#39;characters per line&#39; integer as the second input. Run the subroutine and voila, you get back your original string but with tags inserted in strategic places to force wraping in the designated tag. And it does work. Here is a link to a working example:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href=&quot;http://opensite.mobi/cgi-bin/site_wurfl.cgi&quot;&gt;http://opensite.mobi/cgi-bin/site_wurfl.cgi&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Run the above script in a mobile browser and look at the output. This script reports back the &#39;user agent&#39; string it detects, as well as some WURFL data inspired strings. These strings represent the &#39;continuous character&#39; strings I talked about in the beginning of this post. Normally, they wouldn&#39;t wrap and they screwed up the look of the outputed page. And here is a link to the actual script (just in case the above doesn&#39;t work after copy/paste):&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href=&quot;http://opensite.mobi/cgi-bin/site_txt_display.cgi?display_text=wurfl&quot;&gt;http://opensite.mobi/cgi-bin/site_txt_display.cgi?display_text=wurfl&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I scanned the web a while back and couldn&#39;t find anything else available at the time. If you know of something similar, drop me a line or leave a comment. I&#39;m always on the lookout for improvements.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mobilesiteos.blogspot.com/feeds/725979884448189303/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://mobilesiteos.blogspot.com/2009/12/how-to-force-wrap-of-long-strings-for.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4070763839197449611/posts/default/725979884448189303'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4070763839197449611/posts/default/725979884448189303'/><link rel='alternate' type='text/html' href='http://mobilesiteos.blogspot.com/2009/12/how-to-force-wrap-of-long-strings-for.html' title='How to force wrap of long strings for mobile display'/><author><name>Dwight</name><uri>http://www.blogger.com/profile/10490400264168860529</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4070763839197449611.post-3502612672320034757</id><published>2009-11-30T14:38:00.000-08:00</published><updated>2009-11-30T14:51:44.397-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Perl subroutine"/><title type='text'>Simple Perl Mobile Device Detection</title><content type='html'>Here is a simple Perl subroutine to try to detect mobile devices from within a Perl script.  This subroutine has been cobbled together from bits and pieces I have found around the web. Let me know if you have comments or improvements to it&#39;s logic.&lt;pre&gt;&lt;br /&gt;sub is_mobile_device {&lt;br /&gt;# -----------------------------&lt;br /&gt;&lt;br /&gt;my $mobile_browser = 0;&lt;br /&gt;my $env_ua = lc $ENV{&#39;HTTP_USER_AGENT&#39;} || &#39;&#39;;&lt;br /&gt;&lt;br /&gt;if ((!$env_ua =~ /linux/) &amp;amp;&amp;amp;&lt;br /&gt; (!$env_ua =~ /win/) &amp;amp;&amp;amp;&lt;br /&gt; (!$env_ua =~ /os\s+(X|9)/) &amp;amp;&amp;amp;&lt;br /&gt; (!$env_ua =~ /solaris/) &amp;amp;&amp;amp;&lt;br /&gt; (!$env_ua =~ /bsd/)) {&lt;br /&gt; # This user agent is not Linux, Windows, a Mac, Solaris or BSD&lt;br /&gt; $mobile_browser++;&lt;br /&gt;}&lt;br /&gt;if ($env_ua =~ m/up\.browser|up\.link|mmp|symbian|smartphone|midp|wap|phone/) {&lt;br /&gt; $mobile_browser++;&lt;br /&gt;}&lt;br /&gt;if ((index lc $ENV{&#39;HTTP_ACCEPT&#39;}, &#39;application/vnd.wap.xhtml+xml&#39;) != -1) {&lt;br /&gt; $mobile_browser += 2;&lt;br /&gt;}&lt;br /&gt;if ((index lc $ENV{&#39;HTTP_ACCEPT&#39;}, &#39;application/xhtml+xml&#39;) != -1) {&lt;br /&gt; $mobile_browser++;&lt;br /&gt;}&lt;br /&gt;if ((index lc $ENV{&#39;ALL_HTTP&#39;}, &#39;operamini&#39;) != -1) {&lt;br /&gt; $mobile_browser++;&lt;br /&gt;}&lt;br /&gt;if ((index $env_ua, &#39; ppc;&#39;) != -1) {&lt;br /&gt; $mobile_browser++;&lt;br /&gt;}&lt;br /&gt;if ($env_ua =~ /ip(hone|od)(;|\s)/) {&lt;br /&gt; $mobile_browser++;&lt;br /&gt;}&lt;br /&gt;if ((index $env_ua, &#39;windows ce&#39;) != -1) {&lt;br /&gt; $mobile_browser++;&lt;br /&gt;} elsif ((index $env_ua, &#39;windows&#39;) != -1) {&lt;br /&gt; $mobile_browser -= 2;&lt;br /&gt;}&lt;br /&gt;if ((index $env_ua,&#39;iemobile&#39;) != -1) {&lt;br /&gt; $mobile_browser++;&lt;br /&gt;}&lt;br /&gt;if (defined $ENV{&#39;HTTP_X_WAP_PROFILE&#39;}) {&lt;br /&gt; $mobile_browser += 2;&lt;br /&gt;}&lt;br /&gt;if (defined $ENV{&#39;HTTP_PROFILE&#39;}) {&lt;br /&gt; $mobile_browser++;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;my $mobile_ua = substr($env_ua, 0, 4);&lt;br /&gt;&lt;br /&gt;my @mobile_agents = (&lt;br /&gt; &#39;w3c &#39;,&#39;acs-&#39;,&#39;alav&#39;,&#39;alca&#39;,&#39;amoi&#39;,&#39;audi&#39;,&#39;avan&#39;,&#39;benq&#39;,&#39;bird&#39;,&#39;blac&#39;,&lt;br /&gt; &#39;blaz&#39;,&#39;brew&#39;,&#39;cell&#39;,&#39;cldc&#39;,&#39;cmd-&#39;,&#39;dang&#39;,&#39;doco&#39;,&#39;eric&#39;,&#39;hipt&#39;,&#39;inno&#39;,&lt;br /&gt; &#39;ipaq&#39;,&#39;java&#39;,&#39;jigs&#39;,&#39;kddi&#39;,&#39;keji&#39;,&#39;leno&#39;,&#39;lg-c&#39;,&#39;lg-d&#39;,&#39;lg-g&#39;,&#39;lge-&#39;,&lt;br /&gt; &#39;maui&#39;,&#39;maxo&#39;,&#39;midp&#39;,&#39;mits&#39;,&#39;mmef&#39;,&#39;mobi&#39;,&#39;mot-&#39;,&#39;moto&#39;,&#39;mwbp&#39;,&#39;nec-&#39;,&lt;br /&gt; &#39;newt&#39;,&#39;noki&#39;,&#39;oper&#39;,&#39;palm&#39;,&#39;pana&#39;,&#39;pant&#39;,&#39;phil&#39;,&#39;play&#39;,&#39;port&#39;,&#39;prox&#39;,&lt;br /&gt; &#39;qwap&#39;,&#39;sage&#39;,&#39;sams&#39;,&#39;sany&#39;,&#39;sch-&#39;,&#39;sec-&#39;,&#39;send&#39;,&#39;seri&#39;,&#39;sgh-&#39;,&#39;shar&#39;,&lt;br /&gt; &#39;sie-&#39;,&#39;siem&#39;,&#39;smal&#39;,&#39;smar&#39;,&#39;sony&#39;,&#39;sph-&#39;,&#39;symb&#39;,&#39;t-mo&#39;,&#39;teli&#39;,&#39;tim-&#39;,&lt;br /&gt; &#39;tosh&#39;,&#39;tsm-&#39;,&#39;upg1&#39;,&#39;upsi&#39;,&#39;vk-v&#39;,&#39;voda&#39;,&#39;wap-&#39;,&#39;wapa&#39;,&#39;wapi&#39;,&#39;wapp&#39;,&lt;br /&gt; &#39;wapr&#39;,&#39;webc&#39;,&#39;winw&#39;,&#39;winw&#39;,&#39;xda&#39;,&#39;xda-&#39;&lt;br /&gt;);&lt;br /&gt;&lt;br /&gt;if (grep $_ eq $mobile_ua, @mobile_agents) {&lt;br /&gt; $mobile_browser++;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;return $mobile_browser;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;div&gt;The output is simple. If a value of 1 or less is returned, the visiter is probably using a full size pc or laptop.  For values greater than 1, the visiter is probably using a mobile device.  It&#39;s not perfect, but gives a quick first cut.&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mobilesiteos.blogspot.com/feeds/3502612672320034757/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://mobilesiteos.blogspot.com/2009/11/simple-perl-mobile-device-detection.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4070763839197449611/posts/default/3502612672320034757'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4070763839197449611/posts/default/3502612672320034757'/><link rel='alternate' type='text/html' href='http://mobilesiteos.blogspot.com/2009/11/simple-perl-mobile-device-detection.html' title='Simple Perl Mobile Device Detection'/><author><name>Dwight</name><uri>http://www.blogger.com/profile/10490400264168860529</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>