Upload files without refreshing the page with just JavaScript

So you want a simple way to dynamically upload a file? Using JavaScript and nothing more? I may have the solution for you... well no, Google has. But I'll just add some details here.

But first, we need to know our limitations:
  • XHR cannot be used to upload files.
  • Even if it can be (which I'm 99% sure it can't), our code will look like shit.
Next, we need to know what we really mean by "simple".
  • Don't want to use Java Applets.
  • Don't want to use Flash.
  • Simple so that it works with FireFox, Safari and IE.
  • Although desirable, simple means there will be no progress bar. However, the file will get uploaded without the page refreshed.
The best way I know that can do the above is with the iframe hack. There are probably several trillion examples out there. However, those that appeared in the first page of my Google search results are either incomplete, hard to follow or they didn't point out the caveats in an obvious manner.

So, here's my attempt using jQuery.

Typically, file uploads are done with a form and a file input. When the form is submitted, the file gets uploaded and the page refreshes with the results. The iframe hack uses that. Except, there is another component. The iframe, of course.

With the iframe hack, you will have your normal form, but the HTML returned by its submission will be 'sent' to the iframe. The iframe is invisible. So users will not see the page refreshed.

So, let's start with an example:

The form

<form id="topsecretuploadform" method="POST" action="/path/to/file/upload/handler" enctype="multipart/form-data">
<input type="file" name="topsecret">
<input type="submit" value="Let the world see it">
<iframe id="topsecretiframe" name="youcannnotseeme" src="" style="display: none;"></iframe>
</form>

You will need some JavaScript to set the target of the form.

You need to set the target to the name of the iframe. If you do that, the HTML generated by the server after it has processed the upload will be sent to the invisible iframe.

jQuery(function($) {
var iframe = $("#topsecretiframe");

$("#topsecretuploadform").submit(function() {
this.target = iframe.attr("name");
iframe.get(0).processContent = true; // The use of this flag will be explained
});
})

You will need some JavaScript to tell the user that the upload is complete

jQuery(function($) {
$("#topsecretiframe").load(function() {
if (!this.processContent)
return;

var iframeDocument = this.contentWindow || this.contentDocument;
iframeDocument = iframeDocument.document ? iframeDocument.document : iframeDocument;
var iframeBodyElement = iframeDocument.body;
// The 3 lines above is a really easy and cross browser way of getting the body of the document object of the iframe

// Assuming that we know certain elements will be present in the returned HTML after a successful upload,
// the code below shows how you can know from the script.

var someHtml = $(iframeBodyElement);
if (iframeBodyElement.find("div.successfulupload").length > 0)
alert('Upload done successfully.');
else
alert('Oh shit. Upload went fubar. Look at your logs.');
});
});

Caveats

The reason for the processContent flag.

Some browsers will call the iframe onload function the first time it loads (with empty content). Some don't. If that flag didn't exists, using our example, some users will be alerted of something that haven't even started doing.

Iframe names must be set statically.

Don't do this:
jQuery("iframe.thosehackyiframes").each(function(index) {
this.name = "wahooga_" + index;
});
From my testing, that does not work. Set them in a static way.

So

So, you get dynamically uploaded files without XHR. In between the form submission and the iframe load function call, you can insert all the bells and whistles. You may actually want some sort of animated waiting gif. But that's something I'm not going to talk about.

Hope this helps.

Paying the Price of Ignorance

Once upon a time, there lived a community in a small town by a river. There were not many of them. The whole community was about 60 persons. Everyone lived in harmony with each other. There was little to fight about.

As good as it sounds, the town was not without its problems. It had a poor drainage system. Couple that with how close it was to the river, they had major flood problems whenever the rain kept pouring.

For generations, the people were taught that the flood could not be avoided. The only thing they could ever do was to prevent as much water as possible from going into their houses. And so it was, for many generations. And it worked. At least, before it reached the size of 60 persons.

When there were more people, the deficiency of the poor drainage was even more obvious. There were more trash and houses. The drainage system couldn't keep up. Although raised as a problem every now and then by the community, there were never actions taken to address the drainage system problem. To those who ran the town, revamping the drainage system was too much cost. The flood never happened often enough to justify and every time it happened, the people were able to prevent too much damage.

To some of them, the ever growing population was enough to keep the damages low. People just needed to help each other when there was a flood. Also, the post-flood town rebuilding works really kept them too busy to do anything else.

And that remained for many many years. If there was one thing constant about the town, it would be the way they recovered from the floods. The total damages rose higher and higher as the population grew. The recovery time took longer and longer. Year by year, they got busier and busier.

In short, everyone in the town was minimizing the burn, but never took time to take out the flames. In the end, they got incinerated.

I think, things would've turned out better if:

  • The mayor had admitted the deficiency...
  • and invested early on for a better drainage system, before it became a huge undertaking.
  • The people didn't believe that orchestrated water scooping activities as a testaments to their unbelievable team work..
  • and put their efforts to innovative solutions to the root cause of the problem, not its symptoms.

Live and die by decisions

To some of us, making decisions is probably one of the hardest things we have to do. I guess it's fair to say that we often want to make the best decisions, and if possible, to not be accountable for the undesired consequences. But I find it ironic, because I see decisions as creating consequences. When a decision is made, the one who made it is accountable for the consequences, be it good or bad. That's because he asked for a change the moment he decided, and it's his change, really.

Everyone has to make decisions.

I'm not a decision making guru. I have not made half a billion of decisions. But I've been making some and I've been exchanging a lot of thoughts with people who make a lot of decisions. In all honesty, the methods are crap. Not because they don't work. They probably work very well for those who shared with me their techniques. I think they are crap because everyone makes decisions differently.

Some people make decisions based on a thought process. Some make them based on experience. Some based on hunches. There are probably a lot more... but the methods are not what I'm writing about. I'm writing about what happens after decisions are made.

When you're asked to make a decision, know this:

Most of the time, it does not have to be immediate, but when you make it, it has to be firm. The last thing you want to show your people is that you're an indecisive decision maker. When you make a decision, you set the motion. Everything starts to roll based on what you said. It's a terrible thing to do to tell the motion to stop, rollback so your people could be in for another set back. When you feel that your decision is right and you have justifications to yourself why it is right, stick with it.

Don't doubt yourself every 5 minutes and change the decision every 30. The people who need your decision is not a text editor. You don't type, reread, and backspace all you want. When you have decided, stick with it, and make the best out of it. But of course, you should never be...

A stubborn ass (the animal, but feel free to interpret with the other meaning). Decisions can be wrong. I think it's important to keep an open mind when someone challenges your decision. In fact, I think it's awesome when someone challenges your decision.

I can understand how some of us might feel 'mocked' or disrespected when our decisions are challenged. But think about it in another way. After we have made a decision, can we ever be sure that our justifications for it is the only truth? My take: No. Never.

To me, the only way I can be more confident of my justifications is by them surviving challenges.

But of course, you can't always be wrong. Sure, you've probably made some bad ones, but my observation tells me that if you're smart enough that you're asked to decide on certain things, you will never always make the wrong ones. When your decisions are challenged, communicate properly and let them know your justifications. Feel free to let those who challenge you know why you think they are wrong, if you think they are wrong. Like you and I, they need to make mistakes to learn. If they never make any, they are not smarter than the day they are right.

Of course, if you made a bad decision, the best thing you can do is to admit it. Admitting a wrong decision is not about saying you're incompetent of deciding. Admitting a wrong decision allows its corrections. If you're making a decision for your team, it also sends a stark reminder to your team members that anyone can make mistakes. To some teams, it makes the leader more 'human'.. and being human, that means he's more approachable and also someone they can challenge.

Ultimately, that results in better decisions.

Things to remember when writing dynamic Confluence macros

When writing macros in Confluence that rely heavily on JavaScript, I think it's good to always have a list of do's and don'ts. At least, I have.

Note: This is a product specific application of Cleaner JavaScript with jQuery.

Here's a part of my list (which exists only in my mind and it's quite long, so I'll just name a few that I think are most important).

1. Use the jQuery alias '$'


Because jQuery is 5 bytes longer than $ and we want to keep our content small. '$' is safe to use if you do it correctly. For instance:

jQuery(function($) {
// '$' will definitely refer to jQuery anywhere inside this method and
// you don't have to worry about JS libs like Prototype screwing you
// up unexpectedly.
});


2. Don't use element IDs


Because macros can be included in a page more than once and there isn't a reliable mechanism available to a macro that helps to guarantee ID uniqueness. Use CSS classes to pick up instances of your macro. For instance:

In a macro that generates the following HTML:
<div class="mymacro">
<!-- New functionality -->
</div>


In a static JS resource required somewhere
jQuery(function($) {
$("div.mymacro").each(function() {
// does something
});
});


If implemented right, you don't have to worry about element ID uniqueness or "unexpected" scenarios that can cause duplicate IDs like the usage of {include}.

With that approach, it's much less likely that instances of your macro will interfere with each other.

3. Avoid the use of inline JS


Because things like this doesn't look so nice.

<a class="worldPieceInAClick" href="#" onclick="javascript:foobarThatReturnsFalse()">Print more money.</a>


In the absence of JavaScript (like when your page is emailed), the link should do nothing. That can be done by doing something like the below (based on the code above).

<a class="worldPieceInAClick" href="#">Print more money.</a>


In a static JS resource somewhere
jQuery(function($) {
$("a.worldPieceInAClick").click(function() {
// Do something fun?
return false;
});
});


If the static JS resource is not available, clicking the link is a no-op.

4. JavaScript needs i18n love too.


Have we seen hardcoded user-viewable messages like this?

In a static JS resource somewhere
alert('Uh oh, something is wrong. Duck.');


With code like that, the user won't be aware that there is something wrong if he can't read English. But the problem is, static JS resources are not generated using Velocity, so it's impossible to have a localized version of it? Not really.

Tip: JavaScript can read anything in the DOM. So:

The better way is this:
<div class="mymacro">
<fieldset class="hidden">
<input type="hidden" name="somethingiswrong" value="$i18n.getText('somethingiswrong')" class="mymacro-i18n">
</fieldset>
</div>


In a static JS resource somewhere
jQuery(function($) {
mymacro = {
getI18nMessages : function(myMacroDiv) {
var i18nMsg = {};
myMacroDiv.children("fieldset.hidden").children("input.mymacro-i18n").each(function() {
i18nMsg[this.name] = this.value;
});

return i18nMsg;
}
};

$("div.mymacro").each(function() {
var myMacroDiv = $(this);
myMacroDiv.find("a.somethingiswrong").click(function() {
var i18nMsg = mymacro.getI18nMessages(myMacroDiv);
alert(i18nMsg["somethingiswrong"]);
});
});
})


5. Think about how your macro will look like in PDF, HTML export, Email and RSS


For instance, the hidden loading icon will probably show in RSS.. and in RSS, you don't have CSS (or you have CSS with broken arms and legs).

For trivial macros, I like to have flags that decide whether or not to generate those "active" elements. For more complex ones, I prefer to have a "static" template.

Surviving the resume scan

While I understand the notion of starting a post with "It has been a while since", I really can't escape from it. I've been looking for something to blame for that, but everywhere I look I just see myself. So rather than to start a post with a similar phrase next time, I'll just say "Read the next paragraph", maybe. Since that's for the next, I'm going to start things off. So, it has been quite a while...

Work is always busy for me. But these recent weeks, hectic would be an understatement. There were surges of meetings and interviews that I had to go to that took a lot of time. It's very typical for a meeting or an interview to take up to an hour or two, depending on the agenda or the position that we're looking to fill.

Before interviews, resumes have to be read. Certainly, that is not a specialized task that one does 8 hours a day. It is most probably an additional responsibility of the interviewer.

Despite the squeeze, resume scanning is crucial. It can determine whether the company gets/misses the correct person for the job or if the interview is going to be a waste of time. Unfortunately, depending on the times, there can be a flood of resumes that have to be scanned. When that happens, your resume will have limited time to tell your potential employer why you're the guy/girl for the job.

In other words, your resume will only get 5 minutes of the interviewer's time. Maybe less.

So, to increase your chances in what I would call the 5-minute window of opportunity, you need to help the interviewer to help you. That's pretty much like what Jerry Maguire said. So you have 5 minutes. What should you do?

Have a proper email address


Email addresses like funboy23 at hotmail dot com, ilovedavidarchuleta at yahoo dot com, darkmayor at gmail dot com, c0d1ingu7r at hotmail dot com (my apologies if any of the mentioned addresses are real) look really bad. Why? Because that's almost like walking into someone's wedding with shorts and holding a bottle of beer smelling like a typical public Malaysian toilet. A proper email address tells your potential employer that you're serious. That's important because your potential employer will certainly be.

Move less relevant details elsewhere (or remove it)


Some examples of less relevant details would be your looks, gender, race, home address and hobby. When an interviewer is scanning resumes, he or she is looking for someone that can do the job. How you look, whether you're a male or a female or what you like to do in your free time doesn't tell the interviewer that. In fact, I think in some countries, it's not recommended to have those details in your resume as it might cause some discrimination.

Recent jobs with achievements


Start with the current employment (if any) and the most recent ones dating as far back as appropriate. Unfortunately, there's no hard and fast rule how many years you should go back. However, from what I've seen so far, three to four years is a good enough limit. Most interviewers look at the employment history to see if you're doing things that are relevant to the position they are hiring for in the recent years.

By the way, if software engineer is the position, my personal take is that anything that you've done over four years ago should be irrelevant by now.

It's also important to highlight your achievements in the list. They don't need to be measurable. But being able to tell your potential employer about your achievements is a good thing because they can gauge how competitive you are in the things that you did that are relevant to the position.

Skills set


Again, only list the things that are relevant. I think most of us have a very long list of skills, but in a resume, you should only list those that are relevant to the position you're applying for. While it may be true that some of us have unbelievable Excel hacking skills or insane Word pretty-fying capabilities, they are not related to the position. It scares me sometimes to see those skills listed in a resume. Whenever I see those skills, two thoughts will usually come across my mind.

1. Is the applicant listing those skills just for the sake of filling up the 10-skills list in a resume template?
2. Does the applicant know what he/she is applying for?

Seriously, having a long list of skills does not mean you are immediately in the impressive list. Often, it's better to have a short list of skills that are relevant. Long lists with irrelevant ones actually look bad.

Referrals


I doubt if referrals are ever contacted in the 5-minute resume scan. The information could be used post-interview, however. But I don't think that happens often at all. Personally, I don't think referrals paint an accurate picture of the applicant.

Most referrals are former supervisors or bosses. They are in one family — people that used to work with you in one of your jobs. While I don't think they'll lie, I believe that they are unlikely to provide the complete picture of you that they have in their minds. For many reasons.

If you have to have referrals, try to get customer referrals.

Having a short and accurate resume increases your chances of being selected. It will save your time and the interviewers'. You get good karma from it.

Happy 1234567890!

1234567890 seconds since Epoch!

Zune didn't break, this time

David's 3-step weekend train wreck prevention

If you found yourself having gone through really hectic weekends on some random occasions of retrospection, you'd probably think you'd rather be at work if you have to go through another one. You might also be thinking that you're insane having thought of that, but actually, you're quite sane.

Most of the sane people that I know (yes, fortunately, I do know some insane people — they tell me I'm not) want to have uneventful weekends. Uneventful here doesn't mean that you lie there on a couch waiting for a bum rot. Uneventful means you don't get unexpected events that stress you out in what is supposed to be a "stress recuperation" period.

Here are some events which I categorize as "unexpected".

  • Breakfast, lunch or dinner invitations that can only be attended if I can manipulate time-space.
  • Oh-shit-I-forgot-about-X panic scrambles.
  • Random tasks that I only thought of doing when I look at myself in the mirror in the morning (haircut, etc).


These are the things that will burn your weekends. If you want your weekends to be "uneventful", you have to minimize unexpected events. Here is my 3-step approach to preventing a train wreck weekend.

1. Identify
Before your weekend begins, you need to think about what you want to get out of it. You need to identify your objectives. It doesn't matter if your objectives are too weird to be even thought about (like watching TV in the nude), you really need to identify them. For me, my objective is simple:

  1. Maximize slack time — Means I want to have as much free time as possible in between tasks and the delays on them do not have any significant effects on my next weekend.


With objectives defined, you need to identify what your blockers are. Blockers are the things that prevent you from getting to your objectives. Taking my usual objective above, my blockers are usually:

  • Appointments — They don't die. They just get postponed.
  • Chores — These are elephants. They don't forget about you. When the time is right, they'll stomp on your face.


Once your objectives and blockers are identified, you need to...

2. Plan
To me, planning is an overhead that can only be done on future events that you have a good idea of their happening. If you're planning for unexpected events, you need to stop drinking. Period. Planning for unexpected events is a mistake. If you're planning for something that can't be planned, you're screwed.

So, with that in mind, what can we plan for? Well, bring up your calendar and ask yourself these questions:

  1. What are the things that will happen throughout the weekend? Are they plotted on the calendar? If they are not, do so now.
  2. Look at your blockers list. Are they also on the calendar? No? Do it.
  3. Does your calendar now say you have to manipulate space time? It does? Then do either of postponing or victimize, whichever applicable. If you postpone, make sure it's on your calendar.


Now that you have a rough plan for your weekend, it's time to think about its optimization. How I usually go about this is by location. Which events will happen at nearby areas? It's probably better to block a period of time for events that will happen in nearby areas. For instance, if I need to be at the dentist at 11:00 a.m. at a place which is about 5 miles away from where I am going to meet my insurance agent later at about 2:00 p.m. and I need to have lunch in between, it's probably better to group these events. Why not just:

Reschedule the meeting with my insurance agent to lunch time, at the same area where I am going to see my dentist.

At this point, you may be thinking that rescheduling is an anti-plan. Yes, I admit that rescheduling means that the plan is screwed up, but an early reschedule has almost the same meaning as a far-from-release-date-software-refactoring. Good software gets refactored all the time and that allows for better software. For a plan, an early reschedule allows for better time usage (better plan).

When you ask for a reschedule very early on, you give enough time for the affected people to reorganize their plans. When there is enough time for involved parties to change (plan-wise), time will not be wasted and priorities can be met. It saves on the profanity factor as well.

Now, after you have optimized your plan, you can see where you can spend time achieving your objectives. But wait, it seems now that the objectives have the lowest priority?

Well, actually, no. They're still at the highest. In any effort to achieve certain objectives, there will be blockers to overcome. If you ignore your blockers and just go straight for the objectives, your view on your objectives is tainted. The reason behind that is when you have "achieved" your objectives by cutting certain corners or efforts, what you have achieved is a subset of what you have set out to. That's why I don't consider achieving objectives by ignoring everything else is really achieving objectives.

Cool. There's a plan, now what?

3. Stick
I think, this is the hardest part for most of us — To stick to the plan.

It's quite common that unexpected events happen in your weekends and that you actually want to attend to them. For instance, a sudden invitation to go for some drinks on a Saturday night. If you have the buffer for it, I suggest that you go. But if you don't (the time and place of the invitation collides with what you have on in that period), I suggest that you take a rain check on it.

It's a bit harsh, isn't it? Well, no, again. If you really want to be participating in that Saturday night hangover-in-the-making session, and you think that whatever you have at that time can be victimized, the objectives that you've set for that week are wrong. But didn't I say that unexpected things can't be planned? Yes, I did. However, you can have a backup plan.

If you really want attend the Saturday night session, you must anticipate for it. Instead of plotting one concrete thing for the period of time that you anticipate the drinking session will be on, plot two. For me, I'd first plot a period of time on Saturday night for meeting friends up. Then I'd plot one more thing that I have full control of that I know I can do anytime without affecting anyone.

For instance, I can make any of the following a backup plan:
  • Finish reading XYZ.
  • Clean my room.
  • Gather receipts for the coming income tax scramble.


If drinking does not happen, I can do something with that time — it doesn't turn into yet another unexpected period of time available for something else.

Of course, you don't want too many anticipations to be in your plan. Otherwise, it's as good as nothing.

So there you have it, David's 3-step weekend train wreck prevention.

Why infrastructure is gold

As part of my continuous efforts to settle my imaginary blog debt, I have decided that for the rest of the year, whenever I can, to write blogs about events happening to and around me as soon as they happen.

I returned a call to a friend last night. This friend, who I will call Winston from this point onwards, is one of those friends who you know, that when he looks for you, it is usually of something urgent that requires your assistance.

Winston is now a consultant in his company. It has been long since his last call, but since it's the Chinese New Year holidays now and most of everybody I know would be taking advantage of it, I returned his call with the thought that there must be shit that has happened that I could help with.

So I rang up, and I got to him. His question to me was:

"Can I ask you a Linux question?"

At an instant, I felt a surge of fury. I did not know why then, but now, when I think about it, it must've been caused by one or more of the following factors:



Fortunately, I was able to control the anger and didn't manage to shower Winston with much love. So, I listened and the real question was (in more or less exact words):

"Help! My CVS users can't check out files and the error related to it is sufficient disk space. I've freed up some space in all related partitions, but it still doesn't work. Any ideas?"

The processing model I have in my brain for this kind of situations is a two-part:

  1. Do I care?
  2. If I care, ask for more information. If I don't, offer a generic piece of crap advice and look like I do.


And so I told Winston, "My, that's a strange problem. Probably worth to take a backup of it and rebuild the server". Of course, I am quite sure that the box he is using as the CVS server has no meaningful purposes other than the one that doesn't currently work.

As you would imagine, no one is going to take that crap advice immediately. So the conversation prolonged and in my last-ditch effort, I told Winston to transfer the CVS server to another box so that in the duration he rebuilds the server, his users are not completely blocked... and this was where the point of hell fury started - He told me even more stuff that I didn't care.

He told me that investing on another box can't be justified. Then he went on rambling that his company is no longer the Java-only company that relies on the CVS. He can't afford too much time in that too. He'll probably pass this back to his colleague.

So I just told Winston that if I were in his shoes, I'd rebuild the server. End of story.

I would've questioned his generosity in providing me with more information if he wasn't a friend (or someone who I didn't find the relevancy of ending on good terms with).

What would my questions be?
  • Why on earth is a consultant doing a sysadmin's job?
  • And being totally clueless about it?
  • And being defensive for his incompetencies?
  • And assuming the CVS is only for Java??
  • And doing the consulting shit on me when I told him to transfer the CVS to another server?
  • And who said anything about purchasing another box?


It's easy at this point to say that Winston is the problem. But that would be wrong. It's not his fault. If you look at the first question in the list above, the key is the answer to why a consultant is doing a sysadmin's job (and possibly fucking it up).

The answer is simple: The infrastructure provided for cross-team support isn't strong. Winston's company does not have an internal support team. That's why Winston was screwing up.

In contrast, I am now working in a company that has an excellent support team. Man, these guys are awesome! Not only do these guys free us up from internal maintenance, they also constantly upgrade our infrastructure so we are always supported to perform at our best. Without them, I think we'd be miles behind where we are now. My hat's off to them.

So if you're running an IT-based company, especially in services, please please puhleeze setup a crack support team. They'll do your company a lot of good.