I have no idea when I would ever want to use these, but they are very cool.

<h4>Click Me</h4>
<div id="texteffect" style="width: 200px;height: 200px; border: 1px solid purple; background: #abcdef; cursor: pointer; padding: 2px; overflow: hidden">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur libero sem, fringilla in posuere a, cursus nec felis. Integer eu mi in tortor malesuada pretium vel sed augue. Donec eget convallis tellus. Aenean vehicula nisl ac justo facilisis et bibendum mauris aliquam. Fusce quis dolor sapien, et lacinia lorem.
</div>
var text = '';
$('#texteffect').click(function(){
  if (text){
    $(this).effect('type', {text: text, word: true}, 2500);
    text = '';
  }else{
    text = $(this).text();
    $(this).effect('backspace', {text: '', word: true},  2500);
  }
});

One downside of the virtual keyboard is that it takes over the physical keyboard, so that typing is in the language of the virtual keyboard. This is often an advantage, but I usually want to mix Hebrew and English text. So I modified the program to track the Caps Lock key: if the caps lock key is depressed, then the physical keyboard types in the virtual language; if not (the usual state) the physical keyboard remains at its default. I'm using the new code in the Young Israel Hebrew Keyboard (now renamed the Bililite Hebrew Keyboard).

Continue reading ‘New Hebrew Keyboard’ »

Part of the drudgery of medicine is all the certification and paperwork, and the petty bureaucrats who need to constantly justify their existence by creating new rules. All the rules are well-intentioned, but taken together pave the road to hell—keeping us away from our patients and actually helping people. One such well-paved path is the American Board of Pediatrics which, over the past 20 years, turned board certification from "Take a test" to "Take a test at home every 7 years" to "Take a closed-book test in a secure environment because we can't trust you, every 7 years" to "Take a secured test every 7 years, keep your medical license (even losing it for not paying taxes means you lose your certification), do Board-approved CME, get patient-satisfaction surveys, and do Board-approved quality improvement projects, every 5 years." There's no reason to believe any of this makes me a better doctor but without it, what's the Board for? But enough griping, I may write about this more later.

One of the first things I tried to do when I started at the St. Lukes Pediatric Care Center this fall was improve our asthma management and follow up, so my Quality Improvement project will be the Board's Asthma Practice Improvement Module. It's no different from what I'm doing anyway, with the added fun of filling out data forms online for the Board to adjudicate.

Asthma Management

Asthma is a growing problem in the US, and the NIH has produced a huge (4 MB) report on managing it, with lots of its own jargon. Basically it's a chronic disease that comes in attacks, which can either be in control—only occasional symptoms—or not in control—frequent symptoms. Either way, attacks are treated with rescue medicines, usually an inhaler that relaxes the muscles in the lungs. If your asthma is in control without any other medicines, then you have intermittent asthma. If not, you have persistent asthma and need control medicines to take every day to prevent attacks. The report further divides persistent asthma into grades of severity, but judging severity is inconsistent and largely irrelevant: if your control medicines keep you in control, good; if not, do something more.

Continue reading ‘Better Asthma Care through Technology’ »

Update: Connie Wiolowan of allanguages.info has made some comments and I've updated the post to reflect them. Thanks!

Connie also created a jQuery plugin for the virtual keyboard; see the comment for details.

I like Ilya Lebedev's JavaScript VirtualKeyboard a lot. It's clever, got an elegant UI, allows you to remap the physical keyboard to any language you want, and has an active and responsive support forum. But it's got a few quirks that make it hard to use with jQuery.

  • Virtually no documentation. You have to read the source to get anywhere. But here's a brief introduction (assuming you use jQuery):
    1. Download the package from SourceForge, unzip the tarball and put the whole folder (don't mess up the organization!) somewhere accessible.
    2. Include the script with <script type="text/javascript" src="/path/to/files/vk_loader.js" ></script>.
    3. Have a blank <div> in your HTML that will house the keyboard. I'll use <div id="jsvk" /> in these instructions.
    4. Have one or more <input type="text" >s or <textarea>s that will accept the keyboard input.
    5. In your $(document).load function, include the statement VirtualKeyboard.show($('input')[0], $('#jsvk')[0]).
    6. Other useful functions include VirtualKeyboard.hide() that hides the keyboard and removes it from the DOM, VirtualKeyboard.attachInput($('input')[0]) that leaves the keyboard visible where it was but associates a new input element with it, and VirtualKeyboard.detachInput() that leaves the keyboard visible but removes the association with an input element.
    7. VirtualKeyboard.open is a synonym for VirtualKeyboard.show and VirtualKeyboard.close is a synonym for VirtualKeyboard.hide.
  • The VirtualKeyboard is a Singleton. This means that you can only have one keyboard shown on a page, and the "skin" (the CSS of the keyboard) is fixed at initialization even if you move it around and associate it with different input elements. It also means that if you use the keyboard for different input elements, changing the language for one changes it for all of them. You can get around this by putting the keyboard into its own document and using iframes or popup windows, and the code includes samples for both of those.
  • The package is huge. The "compacted" version is 4 MB. Most of that is the development files, so it's not like every page downloads megabyte files (the largest downloaded file is the keyboard layout package, about 390K), but it's still huge.
  • Part of the reason that it's so big is that it does everything. Lebedev has put an entire Javascript library into this package, including its own event manager that overrides jQuery's. So you can't do $('input').click(function(evt){}) on elements that are attached to the keyboard. You have to use his EM.addEventListener(self.element[0],'click', function(evt){}).
  • Options are too clever by half: he parses the <script src="/path/to/vk_loader.js?query-string> query string to get them. So to set the initial layout and the skin, I used <script type="text/javascript" src="/path/to/vk_loader.js?vk_layout=IL%20Hebrew&vk_skin=flat_gray" ></script>. Options are:
    • vk_skin: name of folder in the /css folder in the package to use for the CSS
    • vk_layout: name of the keyboard layout. The available names are listed on the right hand side of the home page or the project developement page

But these are really minor issues for such a great package, and adapting it to use jQuery isn't that hard (I'm using my textpopup plugin as a base):


<div id="example">
	Example: <br/><input style="float:left"/><input style="float:right"/>
	<br style="clear:both"/>
</div>

var keyboard = false; // VirtualKeyboard is a singleton, so we have to make sure there's just one container
$.ui.textpopup.subclass("ui.jsvk", {
	_createBox: function(){
		if (keyboard) return keyboard;
		var self=this;
		self._super();
		keyboard = self.theBox;
		VirtualKeyboard.open(self.element[0], self.theBox[0]);
		EM.addEventListener(self.element[0],'keypress', function(e){
			if (e.getKeyCode()==27) self.hide();
		});
		return self.theBox;
	},
	show: function(){
		VirtualKeyboard.attachInput(this.element[0]);
		this._super();
	},
	hide: function(){
		VirtualKeyboard.detachInput();
		this._super();
	}
});

$('#example input:eq(0)').jsvk({position: 'bl'});
$('#example input:eq(1)').jsvk({position: 'br'});

Sitemeter works by inserting an image and iframe into your page, so that when the browser retrieves it, sitemeter can look at the referer and know what page was visited. But you can't include image links in an XML or GIF file, so I can't tell which of the bililite webservices are being visited. But behind the scenes, all the files are PHP files, so I can use cURL to get the image file as long as I can spoof the parameters so sitemeter thinks it knows where the request came from. A little experimentation came up with this:

function getSitemeterImage(){
	// the sitemeter image parameters; obtained by inspection
	$opts = array(
		'site' => 's48bililite',
		'refer' => urlencode ($_SERVER['HTTP_REFERER']),
		'pg' => urlencode('http://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']),
		'rnd' => rand()/getrandmax()
	);
	$ch = curl_init();
	curl_setopt($ch, CURLOPT_URL, 'http://s48.sitemeter.com/meter.asp?'.http_build_query($opts));
	curl_setopt($ch, CURLOPT_REFERER, $_SERVER['HTTP_REFERER']);
	curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
	// be nice to the server (http://inanimatt.com/php-curl.php)
	curl_setopt($ch, CURLOPT_USERAGENT, 'Bililite Webservices (http://bililite.com/webservices)');
	curl_exec($ch); // get the image to tell sitemeter that we were here
}

We don't actually use the image; all we want is to let sitemeter know that we want it.

I just started using Sitemeter for tracking page visits (everyone seems to use Google Analytics, but I've used Sitemeter before and am satisfied with what I've got). Sort of depressing seeing a "1" for the visit count, but it's new as of today. Creating a widget to put in the sidebar was straightforward, since I've already created one widget:

/*
Plugin Name: Sitemeter Widget
Plugin URI: http://bililite.nfshost.com/blog/2010/12/26/simple-sitemeter-widget/
Description: Display the sitemeter.com badge in the sidebar
Author: Daniel Wachsstock
Version: 1.0
Author URI: http://bililite.nfshost.com/blog
*/ 

// WordPress 2.8 Widget code based on http://jessealtman.com/2009/06/08/tutorial-wordpress-28-widget-api/
// and http://justcoded.com/article/wordpress-28-multi-widgets/

class Sitemeter_Widget extends WP_Widget{
  function Sitemeter_Widget(){
    $this->WP_Widget ('sitemeter', __('Sitemeter'), array(
     'description' => 'Display the Sitemeter Badge'
    ));
  } // constructor
  function widget ($args, $instance){
    extract ($args, EXTR_SKIP);
    extract ($instance, EXTR_SKIP);
    echo $before_widget.$before_title.$title.$after_title;
		echo "<!-- Site Meter -->
<script type=\"text/javascript\" src=\"http://$server.sitemeter.com/js/counter.js?site=$account\">
</script>
<noscript>
<a href=\"http://$server.sitemeter.com/stats.asp?site=$account\" target=\"_top\">
<img src=\"http://$server.sitemeter.com/meter.asp?site=$account\" alt=\"Site Meter\" border=\"0\"/></a>
</noscript>
<!-- Copyright (c)2009 Site Meter -->";
    echo $after_widget;
  } // widget display code
  function update ($new, $old){
    return array_merge ($old, $new);
  } // options update
  function form ($instance){
    extract ($instance, EXTR_SKIP);
    $this->textElement ('title', 'Title', $title);
    $this->textElement ('server', 'Server', $server);
    $this->textElement ('account', 'Account', $account);
  } // control form
  function textElement ($index, $text, $value){
    $id = $this->get_field_id($index);
    $name = $this->get_field_name ($index);
    $text = __($text); // localize
    echo "<p><label for=\"$id\">$text <input name=\"$name\" class=\"widefat\" value=\"$value\" id=\"$id\" /></label></p>";
  } // textElement
} // class Sitemeter_Widget

add_action ('widgets_init', create_function('', 'return register_widget("Sitemeter_Widget");'));

Short and sweet

I like my virtual keyboard, but I just found this one, which is so much more elegant and general-purpose. But it's huge, and isn't really pop-up (it opens a new window). And I like the idea of learning new techniques. So I'll have to dissect it and steal all the cool parts and make it part of my keyboard. In my copious free time.

My ever-unreliable AT&T 8525 finally had a permanent white screen of death and, rather than be a slave to AT&T forever, decided to get a separate PDA and phone. I bought an iPod Touch and it is a world of difference. Sync'ing it to Microsoft Outlook was automatic (which never quite worked right with Microsoft Windows Mobile!), the software is smooth and slick (everyone knows that), and it even gets daylight saving time right! ePocrates works, and there's lots of medical software out there. The only thing missing is Riley Kidometer, which I was running under a Palm emulator. It gives age-specific parameters for things like height and weight and a ton of other pediatric-relevant information. I'm getting around it with growth charts from statcoder. The only other things I need from that program are peak flows, which I am serving with the bililite webservices, and the EKG parameters. I'll have to look those up and add them to the webservices.

And having an MP3 player is cool, too.

The best part has been Apple customer service. 2 weeks after I bought the thing, I dropped my iPod on the workshop floor. The glass shattered (I know, I should use a case and not keep it in my shirt pocket when leaning over. פראקטיק שולע איז די בעסטע שולע אבער די פרייז איז זייער טייער—Experience is the best teacher but the tuition is astronomical). Made an appointment at the Apple Store, got the lecture that dropping the iPod is not covered by the warranty, and the Apple rep gave me a new iPod anyway. Unbelievable! They definitely have a customer for life now.

And restoring from backup should have been a no-brainer, but the new iPod had out-of-date system software. After plugging the new iPod in, I was offered the choice of restoring from backup. But when I selected it, I got an error message that the iPod software had to be updated first, which meant setting it up as a new iPod (one click), naming it (a few keystrokes), updating (one click), "restoring to factory settings" (one click to let the iPod know I would want to restore from backup), then restore from backup (one more click). Everything, even the placement of the app icons and the web pages I was looking at, was restored. Annoying, but not difficult.

I had a terrible time getting the positioning for my textpopup to come out right and my solution was hacky and didn't work consistently. It seems that everyone had that problem, and the jQuery UI team solved it (yay!) for version 1.8. Enter the enhanced position. It does all the work for me and allows for much greater flexibility. One downside is that it won't work on invisible (display: none) elements, so I have to hack it with x.css({display: 'block', visibility: 'hidden'}).position(positionOptions).css({display: 'none', visibility: 'visible'}).

The other downside is that the display animation isn't as elegant: my hack involved appending the popup directly after the input box and setting the css so that the correct edge was fixed to the input box. This meant that changing the size of the popup automatically moved it into position, and the animation always appeared to grow out of the input box. Now the position is fixed absolutely, and the standard show always grows from the upper left corner. You have to manually set the animation or reposition the box. A small sacrifice for "just works."

Now, this is cool:


<p contentEditable="true">This is a test (click me)</p>

I was looking for a in-line editor (on the order of jEditable) but it turns out all the modern browsers have it built-in.

However, my sendkeys plugin doesn't work and the position of textpopupup is messed up:


<p id="hebrew" contentEditable="true">This is a test (click me)</p>

$('#hebrew').hebrewKeyboard();

More stuff to work on. Sigh

Update 2010-11-21: new textpopup now is positioned correctly. Now to update the documentation and fix sendkeys.