I guess there’s no such thing as a secure PDF

I was reading the SCORM 1.2 reference docs today. I wanted to copy a passage for my notes, but the PDF is password-protected and prevents anyone from copying text. (REALLY irritating, considering the ADL is a quasi-government organization and the docs should be open to all.)

What to do? Well, turns out there are at least two super easy ways to bypass the password protection: Upload it to Google Drive or import it to Evernote.

Google Drive

The Google Drive site includes a built-in PDF reader; when I opened the PDF in the web viewer, I was able to copy text freely. Better yet, I was able to save the PDF as an unlocked file by selecting “Print” then choosing “Save as PDF” in the print options.

Evernote

When dragging the file onto the Evernote app (Mac), the PDF shows up in a preview window. I was able to copy text freely. No need to save as a PDF since it’s already stored in Evernote!

Security, schmescurity

So I guess there’s no such thing as a secure PDF. I’m sure there are other services like to Google Drive and Evernote, and there are definitely other techniques for defeating protection, including screen captures, OCR, and the old fashioned approach of printing to paper then scanning the prints. If you truly need a document to be secure, don’t distribute it electronically.

Setting OS X Desktop Picture Based on Time of Day

I recently changed jobs (Hello, FireEye!) and was issued a new MacBook Air. I spend a lot of time looking at the screen and was getting bored with the supplied desktop pictures. I also start work very early most days (7am-ish), and thought it would be nice to have a desktop picture that matches the mellow-ness of such an early hour.

Of course, this leads to daydreaming — “scope creep” in professional parlance — and next thing you know, I started thinking “well, maybe I could also set it to show a nice evening-themed picture at night”. Then “maybe I can get it to change both screens” (I use a laptop with an external display).

I also liked the challenge of putting together a script as quickly as possible. (In my off-hours, of course!)

I downloaded some nice wallpaper images from National Geographic, then created six folders that correspond to the major periods of the day: morning (early and late), afternoon (early and late), and evening (early and late). I organized my National Geographic photos into those six folders, based on the mood each photo evokes. For example, this one is an early morning photo.

Then I rolled up my sleeves and got out the trusty old AppleScript Editor. The resulting AppleScript is posted on GitHub, if you’d like to take a gander.

The gist:

  • It selects a folder based on the time of day.
  • It randomly selects an image from within that folder and displays it as the desktop picture.
  • It supports more than one monitor, with an option to either display the same image on all monitors, or display different images on each monitor.

The resulting AppleScript must be run at a regularly scheduled interval. I’m currently using GeekTool to run the script every 15 minutes, but I might eventually switch to a crontab job for less overhead.

Regardless, I’m quite happy with the way it turned out, and have already started daydreaming about other things I can hack together with AppleScript.

Importing Google Contacts into iCloud

I signed up for the new iCloud service, and wanted to sync my Google contacts so they will show up on my various Apple devices. MobileMe, iCloud’s predecessor, had built-in support for syncing with Google accounts, so I assumed iCloud would be a no-brainer. Unfortunately, it turns out iCloud does not auto-sync with Google.

It’s easy to completely wipe the iCloud contacts and replace them with Google contacts. However, I didn’t want to import ALL contacts — I wanted a curated list of contacts so I won’t have to scroll through hundreds of names just to find a friend’s phone number. Also, like many people, my Google contacts and my iPhone contacts were not quite synced, and I had some contacts on the phone I didn’t want to lose.

I hunted high and low for automated solutions, including software tools, when I realized it’s actually pretty easy to perform a manual sync. The basic steps are:

  1. Import contacts from iCloud into Google
  2. Clear all contacts from iCloud
  3. Replace iCloud contacts with a curated list of contacts from Google

I expanded the tasks into ten steps, listed below. They look more complicated than they really are — the entire process should only take you around 5 minutes, unless you get caught up in cleaning your Contacts list, which in my case took over an hour!

Note: These steps assume you’re on a Mac, you’ve already set up iCloud on your Mac and iDevices, and all of your devices are synced. All we’re doing is adding Google contacts to the mix.

The steps

  1. On your Mac, Launch Address Book.app and export all Address Book contacts to vCard format.

    Edit > Select All, then File > Export > Export vCard

  2. Take a deep breath, then delete all of the contacts from Address Book.app. This will also automatically delete all contacts from iCloud. (Obviously you should only do this if you’ve confirmed your export in step 1 was successful.)

    Edit > Select All, then Edit > Delete Cards

  3. Launch a web browser and log in to the Contact Manager for your Google account.
  4. Clean up your contacts in Google Contact Manager. This makes it easier to sort through them later. The most important thing is to merge all duplicates where possible.

    More > Find & merge duplicates…

  5. Create a new group in Contacts Manager — I named mine “Sync with iCloud” — and add any contacts you would like to import to iCloud. This enables you to selectively import contacts from Google to iCloud. If you want to sync ALL of your contacts, you can probably skip this step.
  6. Import the Address Book vCard you created in step 1 into Google Contact Manager. This will ensure you don’t lose any contacts that were on your Mac/iPhone but not in Google.

    More > Import

    Upon successful import, you’ll notice Google Contacts Manager has created two new groups: “cards” and a group with today’s date with a name like “imported on [date]”. These two groups are identical, so I’m not sure why Google creates both of them.

  7. Perform another ‘merge’ to clean up any duplicates you may have created by importing your Apple contacts.

    More > Find & merge duplicates…

  8. If you’re being selective about your contacts list, sift through the new ‘cards’ group, adding any desired contacts to your “Sync with iCloud” group.
  9. Once your “Sync with iCloud” group is pruned and ready to go, export it to vCard format.

    More > Export…

    Make sure you select your iCloud group from the drop-down menu under “Which contacts do you want to export?” or else you will be exporting every contact in your Google Contacts list. Of course, if you’re going to export all contacts, go ahead and select the entire “My Contacts” list.

  10. On your Mac, drag the vCard onto Address Book.app to import the contacts. They will sync with iCloud almost instantly.

That’s it! You’re done. It isn’t a perfect process by any means, but it enabled me to merge my Apple Address Book with my Google Contacts, then import only the important contacts back to iCloud.

Drawbacks

1. This is a manual process, so any changes to iCloud will not be reflected in Google and vice versa.

2. The creation of the three new Google Contacts groups is a bit messy. Once I was done with step 10 above, I deleted the two groups created by the vCard import. This isn’t necessary, but I found them a little annoying to look at.

Dear Apple and Adobe

 

Update: Steve Jobs Responds! Well, not to my letter directly, but it hits on the major points and is a well-written explanation of Apple’s position.

Dear Apple and Adobe

I’m a long-time customer and have spent more money on your products than I have on just about any other aspect of my life. I’ve spent more money on your products than I’ve spent on my healthcare, vacations, kitchen appliances, children’s school supplies, or home entertainment system.

In return, you’ve increasingly shown a disregard for my needs and concerns, and have acted in ways that demonstrate all you want from me is my money.

For example, both of you have constantly forced me (or at a minimum pressured me) to buy updates to products I already paid for. For years I went along with it because I bought into the sales hype and assumed these updates would somehow make my life better.  In most cases, they did not.

Adobe, your constant tinkering with the Creative Suite has brought a few nifty tools to the world, but these new tools will not get me to overlook the incredible bloat you’ve unleashed on my computers — almost 6GB of program files on my Windows PC at work, and over 7GB of app files on my Mac at home. Your applications feel more unstable with every release, and your UI feels slow and unresponsive despite the extra RAM and other hardware upgrades on my machines. Some of the biggest security holes on my computers are due to your Acrobat software — the very same Acrobat software I’ve learned to hate because of how bloated, complicated, and unfriendly it has become. It feels like it gets worse with each release.

Apple, your innovation is refreshing. Adobe could learn a thing or two by examining your software: increased productivity through reduced feature sets and cleaner UI. Simple is usually best. However, despite your continued excellence in design, your behavior is repulsive. You’ve consistently screwed your early adoptors via your pricing schemes and forced millions of Americans to use a phone network they detest. (Why? Because AT&T was willing to give you a bigger cut of the revenue?) Worst of all, the totalitarianism displayed in your latest iPhone developer agreement is breathtaking. It appears your goal is to piss off everyone, even your staunchest allies… like Adobe.

Apple and Adobe, you used to play well together. You both benefited from your long-term relationship and grew into very large, very successful companies. I sincerely doubt either of you would have survived the 1990s intact if it weren’t for your partnership. Desktop publishing was the Mac’s forte and the one thing that kept it afloat when the buzzards were circling. And who provided the most popular DTP software? Adobe (and the companies Adobe acquired, like Aldus and Macromedia).

Adobe, I know you’re mad because Apple won’t let you put your Flash technology on the new iPhone platform (iPhone, iPod, iPad). Honestly, if I were controlling a platform, I would have major concerns, too. As I mentioned earlier, your track record for software quality seems to be in a steady decline. Your products have become infamous for security holes, bloat, and crashing. It didn’t used to be that way. Somewhere along the line you dropped the ball, and now it’s coming back to bite you. The good news is that it isn’t too late for you to reign things in and regain control of your software. Stop trying to please everyone by adding every conceivable feature under the sun, and really focus on the most important elements. Drop the cruft. Clean the cupboards. Get that lint out of your bellybutton. Once your software is respectable again, you’ll be in a much stronger position to complain about Apple.

Apple, I don’t know what happened to you. You went from being a popular underdog to being the class bully. You’re in danger of becoming as popular as Microsoft in the European court system. From where I sit, your biggest mistake has been the idea that you can take over the world, one industry at a time. Of course, many companies are aggressive and set big goals for themselves, but they don’t stab their partners in the back as quickly and viciously as you seem to do. Your hubris and eagerness to expand into your partners’ markets is going to be your downfall. People have liked you because of your design sensibilities and because you were the hip underdog. You are no longer the hip underdog, and with time, other companies will create products that will be (almost) as stylish but also cheaper and with equivalent or greater capabilities.

The bottom line is that neither of you are choir boys, and I’m fed up with your bickering.

Adobe, stop playing the sympathy card. It’s a complete turn-off because I know how crappy your software can be. Granted, it’s unfortunate that so many people depend on Flash and Flash doesn’t work on the iPhone platform, but Flash is not a web standard. For all its shortcomings, the iPhone platform has one excellent quality: a top-notch HTML5 browser. Standardistas have been warning people not to go all-in with Flash for years, and now we see why. If it isn’t part of a standard, it will not be incorporated into some products. It’s the vendor’s choice. Simple as that.

Apple, stop trying to take over the world. We’ve seen what happens to other companies who try it, and it never looks pretty. Focus on your core values and let your partners do their thing without stepping on their toes.

Oh, and ditch AT&T already, will ya?

Respectfully,

Philip

Accessibility development tools

There are a great set links for free development tools (validation services, browser toolbars and plugins) posted on the Web Access Centre Blog today:

Looking for alternatives to Bobby and WebXact? Try these!

Anyone familiar with accessibility should already know about Cynthia Says and a few of the web-based validation services… what I was impressed with were the links for the browser add-ons, specifically the Web Accessibility Toolbar for IE. It’s very similar to Chris Pederick’s popular Web Developer Toolbar extension for Firefox (which I use religiously), and is a nice upgrade from Microsoft’s ho-hum IE Developer Toolbar. Lastly, Jon Gunderson’s Firefox Accessibility Extension is another great Firefox add-on.

Check out the other links mentioned in the blog post, and the Web Access Centre’s site when you have time.

Tip: Quick and efficient screenshots without special software

I’ve noticed many people use programs like TechSmith SnagIt to get screenshots. While SnagIt is a fine program, I think in many cases it’s overkill. Here’s a really simple way to get screenshots without needing any special software.

  1. Grab screenshot using Print Screen.
  2. Paste screenshot into Paint.
  3. Save in your preferred format (TIF, BMP, GIF, JPG, PNG, etc.).
Note: Apple Macintoshes come with the utility “Grab”, which is pretty nice and easy to use.

Print Screen

In the old days, pressing the keyboard key “Print Screen” literally meant “make a printout of screen.” Nowadays, it means “take a snapshot of the screen and place the snapshot on the clipboard.” Once it’s on the clipboard, you can paste it into any program that accepts images, such as Microsoft Word, an email program like Outlook, image editors like Photoshop, and even specialized production software such as Flash or Illustrator.

The biggest headache people usually face is editing the screenshot once they’ve pasted it into their program of choice; many times you only want a portion of the screen, not the contents of the entire monitor. Tip: Holding “Alt” on your keyboard while pressing “Print Screen” will only capture the active window. See the illustration below. This can save you a ton of time if you’re taking a lot of screenshots.

Illustration of the difference between using Print Screen and ALT + Print Screen
Use the ALT key to limit the screenshot to the active window instead of the entire monitor.

Pasting into Microsoft Office Documents — Beware!

Microsoft Office’s default document resolution is 96 pixels per inch (ppi). However, all major operating systems (Windows 200/XP/Vista, Mac OS X, Linux) and all major web browsers (Internet Explorer, Firefox, Safari, and Opera) use a default of 72ppi. When pasting a 72ppi screenshot into a 96ppi Microsoft Office document, MS Office automatically scales/stretches your image to match the document’s resolution, often rendering the image blurry or distorted.

Sample image illustrating how Word makes screenshots look blurryScreenshot pasted directly into Word. Notice how blurry it is.

What does this mean for you? It means you should never paste your image into Word or PowerPoint unless that’s the image’s final destination.

If you need to send someone a screenshot for them to use in whatever program they use (InDesign, Illustrator, Dreamweaver, Photoshop, Fireworks, etc.), you should send it as an image file, such as a TIFF, JPG or PNG. DO NOT paste the image into Word or any other MS Office application.

How Do I Make the Screenshot Look Crisp in Word?

If you intend to use your screenshot in Word, you should prep the screenshot by changing its resolution to 96ppi without resampling the image, then import the image into Word (don’t use ‘paste’).

Changing the image’s resolution will require an image editing application such as Photoshop or Fireworks. Trust me, it’s easier than it sounds. Here are the steps:

  1. Paste the screenshot into the image editor (in this example, Photoshop)
  2. Go to the image’s properties and change the resolution from 72 to 96. (In Photoshop, go to Image > Image Size, and be sure to UNcheck “Resample image”)

    Photoshop's Image Size settings

  3. Save the image in a Word-friendly format. I find BMPs work the best.
  4. Go to Word, and select Insert > Picture > From File
  5. Choose the image you just created and click OK.

Your result will look something like this:

Comparing the two different images in WordTwo screenshots: one edited to be 96ppi then ‘inserted’ into Word (left), and one pasted directly into Word (right).

Big difference, eh?

A Tale of Two (or more) Computers

A computer is born, and another computer dies (“I’m not quite dead!” he says in his best Eric Idle imitation).

(Mac) Hi, I’m a Mac.
(PC) And I’m a PC.

I’m sure all of you know this commercial by now. As with many other geeks around the world, I started salivating with the advent of Intel-based Macs that can run Windows natively. Mmmm… Maaaac…

And to me, it’s funny that many of my coworkers and friends are surprised at my interest in the Intel Macs. You see, these days I’m known as a PC guy; everyone thinks that’s how I got started, and that I’m a total Windows nerd. Even my stepkids. [I’m trying hard not to yell “WELL, I’M NOT” right now.]

This is probably because I build my own PCs, by which I mean I buy parts and assemble them. These PCs are used for everything from my workstation(s) to my arcade cabinet. At last count we had six functioning PCs in our house (2 laptops and 4 custom PCs for anyone keeping score).

But I wasn’t always Mr. PC.

Let me take you back in time, to 1990. My stepfather, who has his own business, has been an Apple user since the green-screened Apple IIe. Around 1990 he was using an Apple SE, and decided to get a PowerBook. It was easy enough to use, and I typed a few (very few) high school papers on his Mac. I was also a guitarist in a rock band; one day we needed to make some flyers for a gig, and somehow I wound up using my stepfather’s Mac to make the flyer. A romance was born.

In the late 80s and early 90s, my brother had been a total PC guy (he aspired to be a computer programmer), and was always telling me how many great things you can do in DOS. I was highly bored and uninterested. The closest I had come to DOS at that point was a Commodore 64 in middle school. The Mac had a nice GUI, and was fun! (See any parallels to e-learning, anyone?)

Over the next decade, I worked as a prepress typesetter/graphic designer. Not surprisingly, I was a staunch Mac user and advocate. I graduated from OS 6 to OS 7, then OS 7.5, which I highly enjoyed. Around OS 8, when the PowerPCs came to life, things started becoming less fun for me; it seemed my Mac was crashing more often, the computers were getting more expensive, and with each new OS, the software I owned would stop working! Being a poor student at the time, I couldn’t afford a nice new PowerPC, and prayed Apple would let other computer companies start making Macs, which I had hoped would drive the price down. Sure enough, they tried, but it was a short-lived affair with a messy divorce.

By OS 9 my Mac (my 4th Mac in 10 years, I think) was barely functioning. Even the Macs at school kept crashing. I was also increasingly frustrated at the lack of software titles available for Macs. The few you COULD get were much more expensive than their PC counterparts.

At this point I had dabbled with Windows PCs a bit at work, and was forced to use Windows 98 at one of my jobs. I was pleasantly surprised that my beloved Adobe and Macromedia products worked just as well in Windows as they did on a Mac! But I still refused to give up my Mac at home.

In 2000 I wanted to get another Mac, this time one that could run audio software such as ProTools; I wanted a DAWto do computer-based multi-tracking, but they were WAY out of my price range. ProTools systems at the time were around $10K, AND ProTools was only supported on a select number of Mac models. Sheesh.

One day I complained about it to my PC-loving brother, who whispered in my ear “build your own computer! It will be cheaper, you can just get the parts you need, and you can control the quality of the components!”

I thought about it and realized that while audio recording software had long been the domain of Macs, things were changing. The tide was shifting, just like how Adobe and Macromedia made their products work great in Windows.

I took the plunge and built my first computer. It was easier than I expected, and probably 1/3 the price of a comparable Mac. I embraced the extensibility and flexibility of PCs (though I’ve never loved Windows), and gave up my Mac allegiance. That’s right, I went to the Dark Side. Besides, Steve Jobs was back and putting out a new operating system every 6 months; I was tired of keeping up and couldn’t afford it anymore.

Fast-forward to today: my 6 PCs all run some version of Windows, though I’ve got Ubuntu (Linux) here and there. But something has changed inside me. I’m tired. I’m worn out. Windows is stale as hell, and after seven-plus years, I’m still building and rebuilding computers… it feels like it never ends. Sometimes I find myself thinking it sure would be nice to buy a pre-configured system so I don’t have to work under-the-hood anymore. I want to be a user, not a builder. I see entire Dell computer systems going for less than the price of my computer monitor in 1999.

And I see Intel Macs.

Mmmm… Maaac…

My birthday was in November, and guess what I did? I finally bought myself a Mac for doing audio production! I bought an Intel iMac with 4GB of RAM and a 500GB USB drive, and it cost less than my PC laptop from 2004. Sweet. I felt as if a new world was dawning.

As I unpacked my iMac (which the wife refers to as the iMistress), I dreamed that the days of configuring my computer, spending hours installing software, and all the other tedious ‘administration’ stuff was gone. If you’ve ever unpacked these new iMacs, you’d think the same thing: they’re ready-to-go out of the (very pretty) box, with only ONE cable to plug in, aside from the mouse and keyboard. I had it unpacked, assembled, and turned on in about 5 minutes. Mmmm… Maaaac…

Then something funny happened; I checked the OS software version and discovered that my NEW iMac didn’t have the latest flavor of OS X installed! I had to WIPE THE HARD DRIVE AND DO A CLEAN INSTALL! D’OH! This is something I had done a million times on my PCs, but nonetheless, I thought was behind me.

And let me tell ya something, Mac OSX does NOT install any quicker than Windows XP. Actually, If I had to bet money, I’d say Ubuntu is the easiest OS to install, hands-down.

Installing Logic Pro (audio software) took over FIVE HOURS. Oh.. my… God. And am I the only Mac owner who hates iTunes and likes two-button mice?

But this is a tale of TWO computers… so let’s get to #2: my Windows workstation.

I use this computer for everything, from general email and web surfing to critical development projects. It’s my cornerstone. And it died unexpectedly Saturday night. I’ve been troubleshooting PCs for years, and for the life of me I couldn’t figure out what was wrong with this PC.

I started wondering if it was a sign to go out and buy that pretty MacBook Pro I’ve been flirting with. Since it’s an Intel Mac, I can install Windows on it and use all of my existing software. It even has a DVI port and can run my 21″ widescreen LCD. But on reflection, I wondered if it would be any better than my iMac (which in case you’re wondering is in a different part of the house and reserved for my audio work).

Just as I was about to throw in the towel and pay a visit to the Apple store, I discovered the problem with my PC: corrupt RAM. An easy fix.

So there goes my half-baked dream of becoming all-Mac, and here comes yet another trip to the PC store to get some RAM… and maybe a few other components to tinker with when I have time. 🙂

Oh, and in case any of you are wondering why I’m not responding to your emails, it’ll probably take another night for for me to install all of the Windows service packs and security updates, then another 2 nights to reinstall all of my production software. Should be a blast. Not.

LMSs are just websites… no, really!

I had an interesting conference call the other day regarding a learning management system’s browser support. We’re trying to implement a new LMS, and it needs to be accessible for Mac users. The vendor promised us Mac support before the contract was signed and — surprise! — it doesn’t support Macs at all. It doesn’t even run in Firefox on a PC. (Gotta love sites that still use ActiveX and restrict you to Internet Explorer on a PC.)

So we had an internal conference call to discuss the issue, and I was trying to explain to some cross-town colleagues that a well-made LMS should adhere to web best practices, and by nature should be platform neutral. After all, an LMS is just a website, and should work in any browser.

Then one of my colleagues blurted out “an LMS ISN’T a website!” I was flabbergasted. I mean, I know LMSs seem complicated and all, but they have a web-based front-end and a database back-end, just like any corporate or retail website. When you boil it down, even Amazon.com is just a website (ok, a very complicated one, but a web site nonetheless).

LMSs are basically HTML (often delivered via PHP or ASP), a database, some CSS, some JavaScript, and maybe a little XML for good measure. There is no reason anyone should be using proprietary and browser-specific code in a website, especially in an LMS that should be as accessible as possible, allowing your training courses to reach the widest possible audience.

*Sigh*

Her comment really struck a nerve with me. Over the last year, I’ve learned that many of the people involved in bringing an LMS to a company are NOT technical people. Many of them don’t understand the basic technology involved, and even fewer have any grasp of best practices and standards for web-based technology. The key decision-makers are often basing their decisions on what the vendor has promised the LMS can do — usually in a series of sales pitches and extremely controlled demos — not the recommendation of the technical people who will be using the system on a daily basis… like me!

And I’m pretty sure this is the case at MOST companies, not just mine.

It feels like someone bought us a used car from a shady dealer:

  • without having our in-house mechanic look under the hood (“Why should he look at it? I’m buying it from a dealer, so there’s a warranty!”)
  • without taking it for a test drive (“When the dealer turned the ignition for me in the showroom, it sounded great!”)
  • without checking consumer and professional reviews to see if the car performs well (“Oh, I didn’t know it has a rebuilt Yugo engine… I just saw a picture, and it had a really nice paint job. Plus it comes with a CD player! Didn’t you say you wanted a CD player?”)
  • without checking to see if the person driving it is capable of driving it (“You didn’t say you needed an automatic transmission! Can’t you just learn to drive an 8-speed stick shift? I already signed the lease. What do you mean it’s too small for you? I know you’re 6’5″, but you can still squeeze into a compact car if you need to, can’t you?!”)

…you get the drift.

It’s hard for me, knowing that I will be one of the primary users and administrators of this LMS, and that it doesn’t even meet our most basic need: running in a browser other than Internet Explorer. Again, the vendor said they’d ‘fix’ this, but with proper planning it could have been avoided altogether. And their fix will only make the learner module platform-neutral, not the manager or administrator modules, including the all-important report writing feature… they’ll still require IE on a PC. Bah!

Folks, it’s simple — if you have to paste a “this site works best with XXX browser” message on your site, whether it’s an LMS, an online course, or just a website for your mom’s knitting club, you’re doing something wrong. Do us a favor and stop it.

And if you’ve developed a mega-expensive LMS that only runs in Internet Explorer — especially if you’ve designed it in the last few years — shame on you! You should know better!

Oh, and a side note: my colleagues promptly and authoritatively informed us that they discussed Mac support (specifically Safari support) with the vendor, then did their own research into the ‘major’ LMSs, and no, NONE of the major LMSs support Safari. To which I quietly grimaced, bit my tongue, and slowly walked away from the phone.

I spent the next 60 minutes on google and came up with the following results: of the 15 major LMSs I could think of, 10 clearly state that they support Safari and/or use browser-neutral code. 4 clearly indicate that they do not support Safari, and one LMS didn’t give me a clear indication one way or the other. So that’s roughly 2:1 support for Safari. People, if you’re going to use ‘industry data’ as an excuse for bad programming, at least get some real data. Sheesh.

Assistive computer technology and web accessibility

Just thought I’d pass this link on: http://www.assistiveware.com/videos.php (short write-up here — thanks to Roger Johansson for the link.)

These are video profiles of people with disabilities — mild to severe — who use assistive computer technology to improve their lives. Some people use their computers to simply help them with their jobs (such as a blind person who is a professional French-to-English translator), while others use their computers as a lifeline to the rest of the world.

I want to publicize this link for two reasons: One reason is because the people in the videos are completely inspiring; I can only hope that if faced with a similar situation I can be as positive and productive as they are.

The other reason is because as e-learning/web developers, we have a responsibility to be aware of the needs of people with disabilities, and try our best to make our work accessible. For e-learning and web development, this has become surprisingly easy, yet many developers still don’t do their part, or even realize that what they create isn’t particularly accessible.

Armed with a basic understanding of accessibility, and with a little planning, a web developer can create courses and/or websites that contain rich content — even Flash movies and videos — while supporting a majority of assistive computer/alternative web browsing technologies.

If you Google “web accessibility“, you’ll find a ton of tips and rules of thumb for making websites accessible. Here’s a great starting point: http://www.w3.org/WAI/quicktips/Overview.php

I hope you can spare some time to read a little about the subject; in this case, I think a little knowledge can go a long way. It isn’t hard to make sites accessible, I promise! 🙂

PS – I’m not affiliated with nor do I endorse AssistiveWare, the company that produced the videos.

A cross-browser JavaScript prompt

You might be looking at the title of this entry and say “Well, DUH! JavaScript’s prompt() is already cross-browser!”

While working on a project earlier today, I discovered a nasty little problem… Internet Explorer v7 (IE7) disables prompt() by default! This means you can’t rely on prompt() being available in IE7 when building your online applications.

In most cases, prompt() should be avoided altogether. Maybe Microsoft was right in disabling prompt(), since so many malicious sites take advantage of it. However, I had a legitimate use for it today, and was very irked to find out it won’t work in IE7. (I develop in Firefox and IE6, which might explain to some of you why I’m late to the party with discovering this limitation in IE7.)

After googling for a while — yes, I use google as a verb — it appears quite a few people have developed workarounds for the prompt() limitation in IE7. Most of them were bulky or required a bit too much hacking for my tastes. There were a few nice examples [link no longer available] out there, but in the end, I decided to make my own workaround using Microsoft’s proprietary showModalDialog function.

Microsoft’s showModalDialog allows the developer to load an external HTML file into a generated window and give it focus. The user can’t click back to the original document until they’ve closed the modal window, just like a prompt(), alert(), or confirm(). The generated window behaves much like a pop-up window (it can be sized, show/hide scrollbars, etc.), but to my knowledge, modal windows aren’t blocked by pop-up blockers.

I’ll admit that using an external HTML page feels like a big disadvantage compared to a simple prompt(). However, one potential advantage showModalWindow provides is the ability to style the faux prompt window; in IE, the prompt window has always looked and behaved a little different from any of the other dialog windows (alert, confirm). Now we can have it visually fit in with the rest of the family! Due to this styling issue, and to make my life easier, I decided to use showModalWindow on all versions of IE, not just IE7.

Native IE6 prompt:
Native IE6 prompt

Native Firefox 2 prompt:
Native Firefox 2 prompt

New faux prompt, as seen in IE6:
Faux prompt, IE6

New faux prompt, as seen in IE7 (WinXP):
New faux prompt, as seen in IE7 (WinXP)

Important note: The IE7 modal window will forcibly display the address and status bars if being called by a server (not localhost) which isn’t listed in that user’s list of ‘Trusted Sites.’ This is annoying, but still better than having no prompt() at all. IE6 forcibly displays the status bar, but not the address bar.

Example

Before I dig into the code, here’s a functioning example. There are two files involved in this hack: the main HTML page calling the prompt, and the faux prompt HTML page.

The traditional prompt()

For those of you new to using prompts, here’s an example of a traditional prompt in action:


window.onload = function (){
   var name = prompt("Please enter your name", "");
   if(name){
      alert("You entered '" +name +"'.");
   }
}

Return values

A key feature of prompt() is that it returns the value of the textfield as a string. If nothing was typed into the text field, prompt() returns either null or false, depending on your browser. If the user clicks ‘cancel’, prompt() returns false.

Our faux prompt for IE needs to work the same way. As luck would have it, showModalWindow allows us to specify return values.

Prompt text

Another key feature of prompt() is the ability to display your own text in the prompt, such as “Please enter your name.” To make our lives easier, our faux prompt should work the same way, using the same syntax.

Our IE-specific function: iePrompt()

In all its glory:


function iePrompt(str){
   var settings = "dialogWidth: 290px; dialogHeight: 160px; center: yes; edge: raised; scroll: no; status: no;";
   return window.showModalDialog("iePrompt.html", str, settings);
}

Let’s break it down.


function iePrompt(str){

Since we can’t use the traditional prompt(), we need to create a new, similar function. Just as prompt allows you to specify what text will display by passing a string,

prompt("This text will display in my prompt","")

we want to be able to pass a string in our new function:

iePrompt("This text will display in my prompt")


var settings = "dialogWidth: 290px; dialogHeight: 160px; center: yes; edge: raised; scroll: no; status: no;";

IE’s showModalDialog allows you to style the window much like a pop-up window. The settings are entered as a single string. For convenience and readability, I placed all the settings in a variable named “settings”. You can tweak these settings to suit your own needs. A list of optional parameters can be found here.

Important note: The height of the modal window is set here using dialogHeight; if the display text (in this case “Please enter your name”) wraps to the next line, the window will NOT expand to fit it. If you’re working with long strings, you’ll need to test the height of your modal window, or develop your own sizing routine. Also note that in IE6, dialogHeight referred to the height of the entire dialog window. In IE7, the model was changed, and dialogHeight now refers ONLY to the height of the content. See this IEBlog for more info.

return window.showModalDialog("iePrompt.html", str, settings);

As mentioned earlier, showModalWindow can return a value the same way prompt() returns a value. We want our iePrompt() function to pass the value returned by showModalWindow.

  • iePrompt.html is the name/path of the HTML file containing a form that mimics prompt().
  • str is the text that will be displayed in the prompt.
  • settings is the variable containing the settings string we defined earlier.

The iePrompt.html file

I don’t want to spend too much time explaining the HTML file, as it’s a simple HTML file containing a wee bit of CSS for styling, and a very tiny form. There are some important elements to note, though.

The submit function


function formSubmit(){
   var str = document.getElementById("promptText").value;
   if(str){  
      window.returnValue = str;
   } else {  
      window.returnValue = false;
   }
   window.close();
}

In order to get the showModalDialog function to return a value, we have to make our form return a value. To do this, we have to specifically use window.returnValue. The code is set up to conditionally send either the content of the promptText field, or the value false, just like a normal prompt.

After returning the value to the page that called the prompt, we need to close the modal window by calling window.close.


function formCancel(){
   window.returnValue = false;
   window.close();
}

Prompts also have cancel buttons. We want our modal window to have a cancel button that behaves just like a prompt. To do this, we set up a function that returns the value false and closes the modal window.


window.onload = function (){
   var str = window.dialogArguments;
   if(str){
      document.getElementsByTagName("label")[0].innerHTML = str;
   }
}

This bit of code grabs the display text value being passed by iePrompt and dynamically inserts it into a label on our form. We’re passing the argument using the dialogArguments property of the modal window generated by showModalDialog.


<body onbeforeunload="formCancel();">

Lastly, we need to take into account the fact that many people choose to click the dialog window’s close button (X) instead of OK or Cancel. Using onbeforeunload allows us to call formCancel() if the user decides to close the window.

And that’s it! We now have a functioning prompt for IE.

Putting it into action

Now that we have our custom IE prompt, we need to integrate it with non-IE browsers. Fortunately, this is a pretty simple task.

Determining if the browser is IE

Rather than use some elaborate browser-sniffing technique, we’ll stick to supported feature detection, which is considered a best-practice by the DOM scripting crowd. This is easily accomplished by checking for window.showModalDialog. If the return value is true, the browser is a flavor of Internet Explorer (v4 and higher), and supports our new prompt method. If the return value is false, the browser isn’t IE and should be able to use a traditional prompt().


function cbPrompt(str){
   try {
      if(window.showModalDialog){ return iePrompt(str); }
         else { return prompt(str, ""); }
   } catch (e) { 
         return false; 
   } 	
}

I decided to use a try/catch statement for future expandability (being able to add extra functionality, such as using confirm() to validate the text entered by the user. You could rewrite it to use simple if/else statements.

I wrapped the logic into a new function called cbPrompt (“cb” meaning cross-browser). Now anytime I need a prompt, I simply call cbPrompt instead of prompt():


window.onload = function (){
   var name = cbPrompt("Please enter your name");
   if(name){
      alert("You entered '" +name +"'.");
   }
}

As you can see, it’s almost exactly the same as using the traditional prompt:


window.onload = function (){
   var name = prompt("Please enter your name", "");
   if(name){
      alert("You entered '" +name +"'.");
   }
}

Just remember that you have to ensure the iePrompt.html file is present and that the path defined in the iePrompt function is accurate.

Here’s a fully-functional cross-browser example.