First, let me say that I'm thrilled that Apple finally decided to say something --anything!-- publicly about the topic. Living behind a curtain like that only leads to speculation, and that only leads to worse speculation, which leads to dissent. I know that I've personally started to feel some dissent because of the secrecy; so I'm hoping that more transparency will make things clearer, for better or worse...
Read more →
Posted in
Adobe |
Apple |
Flash
| 17 Responses
April 29 2010
Here's a tip I just figured out for myself this morning, out of necessity. Have you ever wanted to work on one section of a file while looking at another section, hundreds of lines up or down? Scrolling back and forth is a nightmare.
Other editors offer what is called a Split Pane, where you can take the currently open file and divide the window in half, each showing the same file, but each with its own independent scroll bar. Doing this, you can have one section of code in-view, and another that you're working on. This is incredibly helpful.
It's not immediately obvious, but you can do this in Eclipse, and therefore in CFBuilder, too.
The first thing you need to do is clone the tab that you want to split. To do this, choose Window > New Editor from the menu. This will open a 2nd editor (tab) containing the same file, but it won't be split. These two tabs are linked -- changes you make in one are also made in the other.
Next, drag the tab for this new editor to the side of the Eclipse window you want to split. As your mouse approaches the edge of the pane, it will change to an arrow, and there will be a shaded border filling about half the pane, indicating that if you drop it where it is, the editor will fill that border area. Drop it there.
You can split horizontally, as I have here, because I have an enormous monitor and plenty of room:

Or you can also split vertically, if you don't have the horizontal screen space:

Update:
Although it's possible to create split panes as I've illustrated here, the functionality is kind of buggy. If you just need to view or compare 2 sections of the same file, this could be useful; but trying to edit the file in one of the panes seems to cause some strange issues with syntax highlighting, your cursor may disappear, and the pane may just freeze up. I've filed a bug for this behaviour, which I would encourage you to vote for if this feature is important to you. Hopefully this issue will get resolved in a future update.
Posted in
CFBuilder
| 5 Responses
April 28 2010
For a project I'm currently working on, I need to convert relative paths to their absolute equivalent. The paths in question could be for anything: images, JavaScript files, CSS files, etc.
What I want is input of: convertRelPathToAbs('../../../assets/style.css') to output: /myApplication/assets/style.css, assuming that those paths are equivalent, of course.
Because we don't know what to expect, the first thing I want to do is pass-through any external files or paths that are already absolute.
private string function convertRelPathToAbs(required string pathIn)
output="false"
{
var local = structNew();
//if the path is already absolute, just pass-through
if (left(arguments.pathIn, 1) eq '/'){
return arguments.pathIn;
}
//if the path is external, just pass-through
if (lcase(left(arguments.pathIn, 4)) eq "http"){
return arguments.pathIn;
}
Next, we need to get some contextual information. Namely, we need the absolute path of the currently-executing template. This is important because it is how the browser evaluates the relative paths encoded in the HTML. If your page is at http://domain.com/folder/1/2/index.cfm and requests ../assets/style.css, then the browser doesn't request ../assets/style.css, it requests http://domain.com/folder/1/assets/style.css.
In order to make that same conversion in our code, we need the absolute path of the currently executing template and the relative path that needs to be converted. The rest is string comparison and list operations.
/**************************************************/
/**** else... the path is relative, convert it ****/
/**************************************************/
//get the absolute path of the current request to base relative paths from
local.result = getDirectoryFromPath(CGI.SCRIPT_NAME);
Now, start an infinite loop (don't worry, we'll stop it later!):
while(true){
For each iteration of the infinite loop, get the first portion of the path, using a forward-slash as a list delimiter.
local.listTop = listGetAt(arguments.pathIn, 1, '/');
Then, handle different possible values. If its value is just a single period, then that means to use the current folder. We don't need to change anything about our base absolute path.
if (local.listTop eq '.'){
//current directory, just ignore
Then, handle the value ../. This value means we want to go up one level in the directory structure. To do that, we'll delete the last element in the base absolute path.
}else if (local.listTop eq '..'){
//up 1 level in the tree, if possible
if (listLen(local.result, '/') gt 0){
local.result = listDeleteAt(
local.result,
listLen(local.result, '/'),
'/'
);
}
Somewhat simplified, this is referred to as traversal -- we're traversing the path.
The last case we want to handle is something other than a ../ or a ./, which would indicate a folder name. At this point in the relative path, we've stopped going backwards in the directory tree and we want to start going forward. For our purposes, we just need to stop the loop.
}else{
break;
}
The last thing we need to do within the loop is to drop the first item from the relative path (the input) so that the relative path can be appended to the absolute path later and not contain the ./, and close the loop.
arguments.pathIn = listDeleteAt(arguments.pathIn, 1, '/');
}
The above code changes ../../assets/style.css to ../assets/style.css, for example.
There's one last thing we need to account for in the function. There is no leading slash at the beginning of the relative path, which is problematic if traversal takes us to the root of the domain, because the absolute path should start with a slash. We'll start by adding that slash to the beginning of the resulting relative path:
if (left(arguments.pathIn, 1) neq "/"){
arguments.pathIn = "/" & arguments.pathIn;
}
However, when we do this paths where traversal did not go to the root of the domain now contain double slashes, like so: /myApp/1//assets/style.css. Most browsers will handle this just fine, but it's easy enough to fix, so we should. To do so, we just need to remove any trailing slashes from the base absolute path, if they remain:
if (len(local.result) gt 0 and right(local.result, 1) eq '/'){
local.result = left(local.result, len(local.result) - 1);
}
Lastly, return the combination of the modified base absolute path and the modified input:
return local.result & arguments.pathIn;
}
When you put it all together, this is what you end up with:
private string function convertRelPathToAbs(required string pathIn)
output="false"
{
var local = structNew();
//if the path is already absolute, just pass-through
if (left(arguments.pathIn, 1) eq '/'){
return arguments.pathIn;
}
//if the path is external, just pass-through
if (lcase(left(arguments.pathIn, 4)) eq "http"){
return arguments.pathIn;
}
/**************************************************/
/**** else... the path is relative, convert it ****/
/**************************************************/
//get the abs path of the current request to base rel paths from
//local.baseAbsPath = ;
local.result = getDirectoryFromPath(CGI.SCRIPT_NAME);
while(true){
local.listTop = listGetAt(arguments.pathIn, 1, '/');
if (local.listTop eq '.'){
//current directory, just ignore
}else if (local.listTop eq '..'){
//up 1 level in the tree
if (listLen(local.result, '/') gt 0){
local.result = listDeleteAt(
local.result,
listLen(local.result, '/'),
'/'
);
}
}else{
break;
}
arguments.pathIn = listDeleteAt(arguments.pathIn, 1, '/');
}
if (left(arguments.pathIn, 1) neq "/"){
arguments.pathIn = "/" & arguments.pathIn;
}
if (len(local.result) gt 0 and right(local.result, 1) eq '/'){
local.result = left(local.result, len(local.result) - 1);
}
return local.result & arguments.pathIn;
}
This does exactly what I set out to do. Here is some sample input and output:
input: assets/style.css --- output: /test/1/2/assets/style.css
input: ./assets/style.css --- output: /test/1/2/assets/style.css
input: ../assets/style.css --- output: /test/1/assets/style.css
input: ../../assets/style.css --- output: /test/assets/style.css
input: ../../../assets/style.css --- output: /assets/style.css
Notice that it gracefully handles when you attempt to traverse too high in the directory structure. The last two tests have different input but the same output.
Posted in
ColdFusion
| No Responses Yet
April 19 2010
I recently heard about a new website that will show -- at a high level, at least -- what HTML5 features your browser supports, as well as a numerical "score" indicating some percentage of features implemented; with a total possible score of 160.
I should indicate right off the bat (Baseball pun intended. I'll be headed over to Citizens Bank Park to attend the Phillies home opener later this afternoon!) that this is entirely for fun, and not intended to show anything actually useful. This blog post is what happens when professional curiosity intersects with Excel obsession. Please don't read into it anything more than I present at face value.
My opinion on whether Flash is a good platform, or appropriate for mobile browsing, is entirely irrelevant (So let's not bring THAT argument over here, too, ok?). I am, by and large, a supporter of HTML5 and I pray that it lives up to its hype every night at my altar (computer) before I go to bed.
A majority of these numbers were collected from 3rd parties. I don't have all of these phones to test with, for example. I just asked friends who do to let me know how they scored. So in that regard, I can't be sure that the environment was pure or that they were running the absolute latest build, etc.
Disclaimers out of the way, let's talk numbers.

Here are some interesting conclusions I'm drawing from this data:
- The BlackBerry internal browser sucks, and Opera Mini is only marginally better. I can actually personally attest to this, having used a BB Pearl for about 6 months.
- I wholly expected to see IE7, and probably even IE8 toward the bottom of the rankings, but I was greatly surprised to see that IE9 shares the same score as IE8. (If I've done something wrong here, please tell me. All I did was download the latest IE9 preview and open the URL for the test.) Not that I could do any better, but a score of 19 is pretty pathetic compared to some of the other scores. I mean... this was almost beaten by Opera Mini on BlackBerry phones. Really.
- At the bottom of the middle of the pack, is Firefox 3.6.3, which received a score of 101 on both OSX and Windows 7. I expected Firefox to rank higher, (perhaps out of my own personal bias for it as a web developer who loves all of the wonderful features it affords me), but such is life.
- Safari on Windows only scored 70 points. Now, before we draw any conclusions from this, understand that there may be something wrong with the install on my machine here. When I tried to open the test, I was greeted with this lovely error message, twice:
I expected better from the company that is pushing HTML5 so hard, but I suppose it's understandable since the Windows version of the browser is likely a second class citizen in Apple's eyes. So either Apple doesn't care about Windows (much), or there's something wrong with my setup that's preventing part of the test from running. Safari on OSX doesn't score much better, so even if my install isn't perfect, I doubt the Windows version of Safari would outpace the OSX version.
- That said, Safari on OSX is on pace with the iPhone 3G and 3GS. I'm not sure if that speaks well for Mobile Safari, or poorly of desktop Safari. Either way, it's a respectable score; the same way that getting a C on a test is "average". There's nothing wrong with being "average" is there?
- Somewhat to my surprise (though perhaps it shouldn't have been), the scores for the Motorola Droid, and Google's Nexus One mobile browsers (both using the default Android browser) match the current latest stable Chrome build, with a score of 118. There isn't that much of a spread between Mobile Safari and the Android browser. 5 points could easily be 1 or two features.
- And lastly, Chrome is leading the way with what appears to be the highest scores available. I would expect nothing less from Google, who is also pushing HTML5 pretty hard as the future of their cloud-based applications.
If nothing else, this affirms my current tendency of thought that when my AT&T contract is up (in September) that I'll be switching to an Android-based device on Verizon Wireless. At the moment, the front-runner appears to be the HTC Incredible, but 5 months is a LONG time for newer, better devices to make it to market. Who knows what's coming next?
Posted in
HTML/CSS |
HTML5
| 4 Responses
April 12 2010