I've been doing a couple of projects with the Concrete5 CMS recently and it's a joy to use! The template I implemented was designed for the iPad (more on that in another post) so one of the UI elements I wanted to include in the template was a Back button in the header. This would provide an easy way for the user to navigate out of sub-pages within the site.
I sought a little guidance at first and found some good advice in adding breadcrumb navigation in a Concrete5 site.
First of all, add the following lines at the top of your template default.php file right below the defined() function:
$page = Page::getByID($c->getCollectionParentID());
$parent_url = View::URL($page->getCollectionPath());
$nh=Loader::helper('navigation');
$breadcrumb = $nh->getTrailToCollection($c);
Then add the following lines in the place where you want your back button to appear.
if (count($breadcrumb)>0) {
echo 'Back';
}This code should show a back button whenever you navigate past the home page of the site.
I had an odd bug at work the other day. In one of our data reporting systems, the text content for one report was rendering to the browser just fine. But when the same report was exported to PDF using ABCpdf from WebSupergoo some characters were all mangled as shown in the following screenshots:
The messed up PDF output ![]() | The correct browser rendering ![]() |
Well what to do? I didn't even have any idea what the bad characters were but I suspected that they were some sort of UTF-8 abomination of double/single quotes or something of the sort. So here's what I did...
Ah, now we have decimal equivalents for our stange characters. This might be good - where to next? Well, the Replace function sounds like a good bet so I tried...
Text = Text.Replace(Chr(8217), " ' ") which should have replaced the UTF8 appostrophy with the ASCII apostrophy. It didn't ... WTH???!?
After a little more poking around I found out that we need to use ChrW() for character codes in the range < -32768 or > 65535 as described here. Now that we have the right function, our line becomes...
Text = Text.Replace(ChrW(8217), " ' ")
Success!!!! Yeah! Our funky UTF8 apostrophy character now prints as an ASCII appostrophy in our PDF prints.
Thanks for reading!
I've been using a really nice file uploader called Plupload for a couple of years now. It's produced by the same guys that built TinyMCE, it's licensing is cheap and easy, and standard implementation isn't too hard.
What I wanted on my latest project however isn't easily underrstood by looking at the Plupload examples on the site. I wanted a simple drag and drop file uploader like Gmail and Box.net are using. Just a panel onto which you drop files from your OS file manager, then they upload - nothing too fancy but very practical.
Before we get into the code, let's see a quick screencast of the uploader in action.
This first chunk of code initializes Pluploader.
var uploader = new plupload.Uploader({\n runtimes : 'html5',\n url : 'http://mysite.com/js/filemanager/uploadFileHandler',\n max_file_size : '500MB',
flash_swf_url : flashDir+'plupload.flash.swf',
silverlight_xap_url : flashDir+'plupload.silverlight.xap',
button_browse_hover : true,
drop_element : "dropFilesHere",
autostart : true,
container: "fileUploadingContainer",
chunk_size: '1mb',
unique_names: false
});
uploader.init();Runtimes specifies which runtime(s) you want Plupload to use...available runtimes are HTML4, HTML5, Flash, Silverlight, Gears. Drop_element is the id of the div that you want to be the file drop zone. Container is a div that wraps the drop_element div. Make sure that autostart = true.
This next bit of code renders the file names, sizes, and progress bars when the files are dropped onto the drop zone.
uploader.bind('FilesAdded', function(uploader, files) {
var renderString = [];
$.each(files, function(i, file) {
renderString.push('');
renderString.push(''+file.name+' '+plupload.formatSize(file.size)+'');
renderString.push('');
renderString.push('');
});
$('#dropFilesHere').html('').append(renderString.join(''));
uploader.refresh();
uploader.start();
});This last bit changes the size of the progress bar and resets the drop zone after all files have been uploaded.
uploader.bind('UploadProgress', function(up, file) {
var $fileWrapper = $('#' + file.id);
$fileWrapper.find(".plupload_progress").show();
$fileWrapper.find(".plupload_progress_bar").attr("style", "width:"+ file.percent + "%");
});
uploader.bind('FileUploaded', function(up, file) {
var $fileItem = $('#' + file.id);
$fileItem.fadeOut('fast');
$('#dropFilesHere').html('Drop files here');
$('#dropFilesHere').removeClass('hover');
});And that's it! One last thing...to make the drop zone change it's style when you drag files over it, you need a bit more stuff.
$('#dropZoneId')
.bind('dragover drop', function(e) {
$(this).addClass('hover');
e.preventDefault();
})
.bind('dragexit', function(e) {
$(this).removeClass('hover');
e.preventDefault();
});Go download Plupload, put the files on your server and give this trick a shot. It's been tested in Firefox, Chrome, and Safari in XP, Windows 7, and OS X.
Thanks for reading!
On August 15, 2009 Amazon changed the way it accepts API requests. API requests must now be signed using a painful and error prone 10-step process outlined at the Amazon Developer Guide website. There are a few examples for PHP floating around the web right now but I had to try them all and do a little tweaking myself to get this to work. The code below is based on this blog post over at Every Good Path.
I'm not going to explain this line by line but I will say that the following request is designed to search for books by ISBN number and return the book image, author, Amazon link, etc. Have fun!
$request = 'Service=AWSECommerceService&'.
'AWSAccessKeyId='.AMAZON_ACCESS_KEY_ID.'&'.
'Operation=ItemSearch&'.
'Keywords='.$itemISBN.'&'.
'SearchIndex=Books&'.
'ResponseGroup=Images,ItemAttributes,Small&'.
'Version=2009-01-06&'.
'Timestamp='.gmdate("Y-m-d\TH:i:s\Z");
// encode url - replace commas w/ %2C, replace colon w/ %3A
// Could use urlencode($request) here, but $request may already be partially encoded
$request = str_replace(',','%2C', $request);
$request = str_replace(':','%3A', $request);
// break request string into key/value pairs,
$reqarr = explode('&',$request);
// sort on byte value
sort($reqarr);
// tie back together w/ &'s
$string_to_sign = implode("&", $reqarr);
$string_to_sign = "GET\nwebservices.amazon.com\n/onca/xml\n".$string_to_sign;
$signature = urlencode(base64_encode(hash_hmac("sha256", $string_to_sign, AMAZON_SECRET_ACCESS_KEY, True)));
$request .= '&Signature='.$signature;
$request = 'http://webservices.amazon.com/onca/xml?'.$request;
$response = file_get_contents($request);
$amazonXML = simplexml_load_string($response);
Recently, a client was having trouble with an autocompleter implementation I had built for them. This particular application contains a call log module that
allows the client to log every contact made with a customer: phone, walk-in, email, etc. In order to speed up call log entries while on the phone, I created a customer lookup feature that includes an autocompleter on the last name field. The client begins typing in the last name field and a list of potential matches pops up. The client selects the correct customer if they exist, the customer information populates and the client can then begin entering information about this particular contact.
The contact log has reached over 2000 entries by now and there are many customers in the database with similar/same last name. This causes the autocomplete list to extend past the defined height of the container div in many instances which in turn causes scroll bars to appear. Great - everything working as it should. But...in IE 7 and 8 clicking on the scroll bars to view the hidden content causes the div and the autocomplete list to vanish! Oops! In Firefox, everything works fine.
Here's a great forum post on how to fix this problem but I'll lay it out here a little more cleanly. The application UI is built on Prototype and Scriptaculous so we're using Ajax.Autocompleter to make this happen.
We're assuming the autocomplete textbox id is nameLast and the autocomplete div id is nameLastAutocompleter. First, replace your autocompete instantiation code with something like this:
var autocompleteLastName = new Ajax.Autocompleter('nameLast', 'nameLastAutocompleter', memberLookupLastNameURL, {paramName: "autoText", minChars: 3, updateElement: this.returnAutocompleterFieldsMember});
Event.observe('nameLastAutocompleter', "mouseover", autocompleteLastName.onHover.bindAsEventListener(autocompleteLastName));
Event.observe('nameLastAutocompleter', "click", autocompleteLastName.onClick.bindAsEventListener(autocompleteLastName));
if (Prototype.Browser.IE) {
$('nameLastAutocompleter').observe('mousedown', function(e) {
autocompleteLastName.dontBlur = true;
e.stop();
});
$('nameLastAutocompleter').observe('blur', (function(e) {
setTimeout((function() {
if (! $('nameLast').focused)
this.onBlur(e);
}).bind(this), 100);
e.stop();
}).bindAsEventListener(autocompleteLastName));
$('nameLast').observe('focus', function() { $('nameLast').focused = true; });
$('nameLast').observe('blur', function() { $('nameLast').focused = false; });
} else {
$('nameLastAutocompleter').observe('mousedown', function(e) {
e.stop();
});
} Then, at the bottom of the Scriptaculous controls.js file (or any other globally included js file), add the following:
Autocompleter.Base.prototype.render = function() {
if(this.entryCount > 0) {
if (this.selected_item)
Element.removeClassName(this.getEntry(this.selected_item-1),"selected");
Element.addClassName(this.getEntry(this.index),"selected");
this.selected_item = this.index+1;
if(this.hasFocus) {
this.show();
this.active = true;
}
} else {
this.active = false;
this.hide();
}
};
Autocompleter.Base.prototype.onHover = function(event) {
var element = Event.findElement(event, 'LI');
if(element && defined(element.autocompleteIndex) && this.index != element.autocompleteIndex) {
this.index = element.autocompleteIndex;
this.render();
}
Event.stop(event);
};
Autocompleter.Base.prototype.addObservers = Prototype.emptyFunction;
if (Prototype.Browser.IE) {
Autocompleter.Base.prototype.onBlur = function(event) {
setTimeout((function(e) {
if (this.dontBlur) {
this.dontBlur = false;
return;
}
this.hasFocus = false;
this.active = false;
this.hide();
}).bind(this), 100);
};
} It's a lot of code, I know - but it did the trick for me.
I'm pleased to announce that one of our products, CreativePro Office, was featured in a post by the popular Smashing Magazine blog on Nov. 13th.
The post entitled, 15 Useful Project Management Tools, gave CPO good reviews along-side some pretty heavy-hitters including Basecamp, ActiveCollab and Trac Project.
Client tracking is integrated, making this handy for those who work with lots of different clients, and it could even serve as a simple CRM program, depending on your needs.
Integrated invoices and financial information is handy, and the finances page gives you options for viewing and creating invoices, expenses and reports.
CreativePro Office is very robust for a completely free application and is definitely worth checking out before shelling out for an expensive paid solution.
CPO received 14,000 unique visits and 560 new user registrations on the day the article was published. So I just wanted to say Thanks Smashing! We appreciate the plug.
Other UpStart Productions products have been featured in popular blogs. On Jan 23, 2008, our StuffSafe home and office online inventory application was the featured topic in a blog post by Lifehacker.
Years ago I made this little MP3 player button just to fool around with Flash and gain some experience with ActionScript. It's based loosely on the Wimpy Button but with fewer features.
To make this work, just change 1 flashvar that points to the path of your MP3 file like so...
flashvar="soundFile=(path to your MP3 file)"
The path may need to be a full path to the MP3 file even if it resides in the same directory as the SWF file. I'm not sure why but this is something I ran into when deploying this on my webserver.
Thanks and have fun.
Download the SWF and FLA files here.
This is a Flash multi-MP3 player I built a number of years ago. Tracks are added to the playlist through an XML file. Take a look at the file sounds.xml to see how to configure your playlist. Essentially you just add track title, artist name, and MP3 path to the appropriate XML nodes and you're set to go.
Configure only one flashvar to tell the player which XML file to use like this...
flashvar="soundFile=(path to XML file)"
There are a few things that should be fixed to make this player really polished. You'll see what I mean if you play with it for a bit.
Well anyway, it's free so crack open the ActionScript and have some fun making it work better. Let me know if you have any success.

Sylvie Roberta Denton was born on September 30, 2008 at 8:00 am - weighing in at 7lb 12oz. Mother and baby are both doing fine. Of course, she is an exceptionally healthy and beautiful little girl. Expect to see more pics in the near future.
I’m not ashamed to admin that I’ve fought with this problem for months. I’ve always put it on the back burner for a more convenient time, but today I just hammered away until I found a solution.
Now, to some of you (most???) this may seem trivially obvious. The scenario is this…let’s say you have a JavaScript method containing an Ext.Ajax.Request with a callback function. Furthermore, you need to pass a couple of variables to this method and have them processed in the callback function. The scenario in code looks like…
var someClass = {
someMethod: function(var1,var2) {
Ext.Ajax.request({
url: 'someURL.php',
method: 'POST',
params: {param1:'param1',param2:'param2'},
success: function(response) {
// Do something with response.responseText AND var1, var2 here.
}
});
}
}
At first glance this presents a big scoping problem since var1 and var2 are local and available only to someMethod. The answer is the ’scope’ parameter of the Ajax.request object. If we set the scope parameter to someClass.someMethod we now have access to var1 and var2 inside the success callback function.
var someClass = {
someMethod: function(var1,var2) {
Ext.Ajax.request({
url: 'someURL.php',
method: 'POST',
scope: someClass.someMethod,
params: {param1:'param1',param2:'param2'},
success: function(response) {
// We now have access to var1 and var2.
alert('Response = '+response.responseText+' var1 = '+var1+' and var2 = +var2);
}
});
}
}
Adding a Back Button to Concrete5 Template
Remove odd characters from PDF prints in VB.NET
Drag and Drop File Upload with HTML5 and Plupload
Signing Amazon Requests with PHP
The Sciptaculous Autocompleter Disappears in IE!
Coding [6]
coding .net [1]
coding concrete5 [1]
coding php javascript mysql [0]
ExtJS [1]
Family [1]
Flash [2]
Free Stuff [2]
JavaScript [3]
News [1]
Reviews [0]
Reviews Coding [0]
Webusiness [3]
August 2011 [3]
September 2009 [1]
June 2009 [1]
November 2008 [1]
October 2008 [3]
September 2008 [1]
March 2006 [3]