Create a Simple Document Viewer with ExtJS

A document or report viewer is simply a tool that can be used to provide quick, indexed access to various PDF report files, image files or even word documents. You can easily index your documents as you author them but some versions of PDF tools don’t permit this. Another option would be to create a Microsoft Powerpoint slideshow – but this doesn’t give you the left-hand navigation tree capabilities of an indexed Adobe PDF (for example.)

I wanted to create a tool that could be used to provide visual access to many individual documents while presenting an easy-to-navigation tree structure based on the groupings or categories of these documents.

This article will provide the tools and examples necessary to enable you to create a simple, light-weight, portable (zip and go), cross-browser, web-based (serverless) document viewer. The intent is to have an archive that you can mail or carry on a thumb drive and distribute freely to customers, prospects or colleagues to enable quick and easy viewing and access to a collection of PDF or other files.

As I always do… let’s cut to the chase… looking for the downloads or source code?
[download id=”12″]

Before we start, I’ll also point you to the working demo / example.

A west region with a treeview control and a center panel with details that change as you select items from the treeview. This type of interface is ubiquitous and yet creating something like this to simply view documents may seem very difficult for folks that haven’t worked with javascript. The document viewer application was created to provide a mechanism for viewing collections of sample reports.  A design goal for this application was for it to be completely standalone – not requiring any additional software or web server to view the documents.

At the heart of this system is a perl script – parse_csv.pl. This is a perl script that was written to create a javascript object notation assignment (JSON) used to populate a treeview control for the purpose of displaying example pdf reports with previews. In order to use this package to create your own custom file or report viewer, you must create a comma separated value (CSV) file with the following values.

REPORTFILE,PREVIEW,GROUP,TITLE,DESCRIPTION

Column 1 – Report file specifies the name of the PDF report file that will be downloadable from within the viewer.

Column 2 – Preview file specifies the name of the preview or thumbnail image that will be presented in the details pane of the viewer application.

Column 3 – Group specifies the treeview group where this report will be grouped.  You should sort your csv file so that groups are stored together.

Column 4 – Title specifies the title of the report and will be displayed in the details pane of when the user clicks on the report in the treeview.

Column 5 – Description specifies the details of what the report will show.

Example

REPORTFILE,PREVIEW,GROUP,TITLE,DESCRIPTION
reportfile_number_one.pdf,preview_of_report_file_one.png,Group One, Example of a Report File One,This report shows some serious stuff.
reportfile_number_two.pdf,preview_of_report_file_two.png,Group One, Example of a Report File Two,This report shows some more serious stuff.
reportfile_number_three.pdf,preview_of_report_file_three.png,Group Two, Example of a Report File Three,This report shows some more serious stuff.
reportfile_number_four.pdf,preview_of_report_file_four.png,Group Two, Example of a Report File Four,This report shows some more serious stuff.
reportfile_number_five.pdf,preview_of_report_file_five.png,Group Two, Example of a Report File Five,This report shows some more serious stuff.
reportfile_number_six.pdf,preview_of_report_file_six.png,Group Three, Example of a Report File Six,This report shows some more serious stuff.
reportfile_number_seven.pdf,preview_of_report_file_seven.png,Group Three, Example of a Report File Seven,This report shows some more serious stuff.

You may include the column headers in your file – however, ensure that you use the --skipheader flag when executing the parse_csv.pl script.

Requirements
Perl.  The parse_csv.pl script is written in perl so you will need an environment were you can execute perl scripts.  A subrequirement is that I’m using some libraries that you may not have installed in your perl environment.

Checkout http://search.cpan.org if you get some errors about missing libraries.

Here’s an overview of the process to create your own custom document viewer.

  1. Download the [download id=”12″] package.  This will contain everything you need to

create and customize your own self contained document viewer.  Self contained

means that you don’t even need to host these documents and the viewer on a web

server… you can simply open the index.html file from a browser.

  1. Review the directory tree for the example package.
.
|-- css     Style Sheets
|-- extjs    Javascript Library for the treeview and panel components
|-- images    Various supporting image files (like icons, etc.)
|-- js    Javascript source files
|-- reports    Report directory - this is where you'll place the reports, pdfs and preview thumbnail files that will be displayed in the viewer.
|-- scripts    Scripts used to create and customize your viewer
  1. Since you’ll be creating your own document or report viewer, you’ll probably want to delete the contents of the reports directory.
  1. Create the report files that you’ll be displaying in the document viewer.  Report files can be PDF, PowerPoint (ppt) or Word Document (doc) files.  Typically, the report file examples are multi-page pdf files.  Once you have the report files, copy them into the reports directory in the base of the example package.
  1. Create a screenshot, or preview image that will be displayed in the preview section of the details panel when viewing the report.  zScreen is a great, free utility that lets you capture portions of your screen and save them to files.  I prefer ‘png’ format because of smaller size.  You’ll need to create one preview image for each report you plan to display in the document viewer.  Copy or place these preview image files into the reports directory along side the actual pdf or ppt report files.
  1. Now you’ll need to create a comma-separated file that contains the names of your report files, the groups they’ll be displayed in, the document titles and a description of each.  As previously mentioned the format for this file is REPORTFILE, PREVIEW, GROUP, TITLE, and DESCRIPTION.  You can find an example in the scripts directory in a file called example.csv.
  2. Create the documents.js file.  This is the file which contains the Javascript Notation (JSON) which is used to populate the treeview control as seen in this image.  The package contains a script named parse_csv.pl and can be found in the scripts directory of the example package.  This script should be run from the main directory of the archive and must be provided several command line options in order to execute properly.  The following is an example execution of the script:

scripts/parse_csv.pl --csvfile scripts/example.csv --outputfile js/documents.js

This was executed from the base directory of the example archive file.  The –csvfile argument tells parse_csv.pl where to file the csv file that you created in step 5.  The –outputfile argument tells parse_csv.pl where to write the json.

It is important to note that the script assumes that you have not modified the directory layout and that you are storing your reports and previews or thumbnails in the “reports” directory.  You may run the script with “—help” to obtain additional information and options.

$ scripts/parse_csv.pl --help


Usage: scripts/parse_csv.pl --csvfile <filename> [--outputfile <filename.js>]
[--outputfile <outputfilename>] controls the output javascript filename - defaults to stdout
[--reportdir <reportdirectory>] specifies the directory where the pdf files may be stored
[--thumbdir <thumbnailedirectory>] specifies the directory where the thumbnail or preview image files may be stored
[--htmltitle <htmltitle>] specifies the title to be used in the report viewer html file
[[--overwrite] | [--nooverwrite]] - controls whether the output file will be overwritten

The following is an example of the resultant documents.js file that is created.


var json=[{"iconCls":"group","text":"Group One","children":[{"content":"reports/reportfile_number_one.pdf","description":"This report shows some serious stuff.","size":"16.23 KB","published":"01-29-2012","iconCls":"pdf","preview":"reports/preview_of_report_file_one.png","text":"Example of a Report File One","id":"1","leaf":"true"},{"content":"reports/reportfile_number_two.pdf","description":"This report shows some more serious stuff.","size":"16.23 KB","published":"01-29-2012","iconCls":"pdf","preview":"reports/preview_of_report_file_two.png","text":"Example of a Report File Two","id":"2","leaf":"true"}],"id":0.0960750988024337},{"iconCls":"group","text":"Group Three","children":[{"content":"reports/reportfile_number_six.pdf","description":"This report shows some more serious stuff.","size":"16.23 KB","published":"01-29-2012","iconCls":"pdf","preview":"reports/preview_of_report_file_six.png","text":"Example of a Report File Six","id":"6","leaf":"true"},{"content":"reports/reportfile_number_seven.pdf","description":"This report shows some more serious stuff.","size":"16.23 KB","published":"01-29-2012","iconCls":"pdf","preview":"reports/preview_of_report_file_seven.png","text":"Example of a Report File Seven","id":"7","leaf":"true"}],"id":0.119647523478733},{"iconCls":"group","text":"Group Two","children":[{"content":"reports/reportfile_number_three.pdf","description":"This report shows some more serious stuff.","size":"16.23 KB","published":"01-29-2012","iconCls":"pdf","preview":"reports/preview_of_report_file_three.png","text":"Example of a Report File Three","id":"3","leaf":"true"},{"content":"reports/reportfile_number_four.pdf","description":"This report shows some more serious stuff.","size":"16.23 KB","published":"01-29-2012","iconCls":"pdf","preview":"reports/preview_of_report_file_four.png","text":"Example of a Report File Four","id":"4","leaf":"true"},{"content":"reports/reportfile_number_five.pdf","description":"This report shows some more serious stuff.","size":"16.23 KB","published":"01-29-2012","iconCls":"pdf","preview":"reports/preview_of_report_file_five.png","text":"Example of a Report File Five","id":"5","leaf":"true"}],"id":0.423250772097287}]

var htmltitle='Example Report Viewer;'

Notice that the script determines the proper filetype and assigns the appropriate icon class – pdf for pdfs, ppt for ppts, etc.  Also note that the script determines the file size and date created.  These attributes are displayed in the details panel when viewing the documents.

Again… here’s the goods:
[download id=”12″]

WP-ExtJS Version 1.0.4 – ExtJS Pivot Grid Example

In honor of Version 1.0.4 of the WP-ExtJS Plugin being committed this morning, I decided to post a new example. This example shows the powerful pivot grid capabilities in the latest version of ExtJS from Sencha.

 

Grab the Plugin from WordPress.org

 

Please note that you must upgrade to the latest version of ExtJS – Currently 3.3.1.

 

Pivot Grid Example

This example shows how to create a Pivot Grid backed by an Ext.data.Store.

 

Continue reading →

Graceful Sidebar Version 1.0.6 Released

* Update – December, 29th, 2011 *
See http://www.mlynn.org/2010/12/graceful-sidebar-version-1-0-7-released/ for Version 1.0.7

Version 1.0.4 brought custom edit fields so that you no longer have to remember the name of the custom fields to populate in order to create custom sidebars for your posts and pages. Version 1.0.6 fixes the custom field for the sidebar content so that it behaves within the admin edit post screen.

You can download this latest version right from the WordPress Plugin site.

There have been reports of losing the Graceful Sidebar Comment from Posts or Pages when saving posts. I’ve tested this on several instances and cannot reproduce. If you have experienced this, please leave a comment and let me know.

WordPress Extjs – Displaying Posts in an ExtJS Grid

Now that the WP-ExtJS Plugin is complete, I figured, I’d create a post to show a use case. Today, I’ll be showing how you might use this plugin to display your blog posts in an ExtJS Grid using PHP and MySQL – and the WordPress built-in functions for accessing blog post data.

Requirements

Continue reading →

10 Tips to Help You Become a Better ExtJS, PHP, MySQL Developer

Before I begin, let me first say that I am not an expert ExtJS, PHP or MySQL developer. I have however, learned over the years from some basic design principles and tips gleaned far smarter and more talented developers than myself. I thought I’d create a post in the hope that you may benefit from what I have learned. Some of these tips will be pretty basic for most skilled developers, but it never hurts to review, right?

Audience – Who is This Article For?

This article was intended for the novice to intermediate web developer who specializes in use of the following technologies:

Tip 1 – Stop Using Print Statements to Debug

Developing solutions using the elegant Javascript framework ExtJS can be a mix of pleasure and pain.  While debugging the Javascript components is made easy with the handy Firefox extension FireBug, getting debug information back from the php side of your app can be tricky.  Especially if you’re expecting to maintain JSON communication with your javascript components. There are basically two methods of debugging the php side of your app.  You can either rely on JSON encoded strings sent back to your javascript components, decode them on the other side and display them either in and alert window, or in the console using console.log, or you can use print statements in your php.

The latter approach will commands will likely cause a javascript interpreter error and force you to reload the page to continue testing. I prefer the latter approach because its simpler.  However, instead of simply using the php echo or print commands, I like to create a logging function which uses file_print_contents to populate a debug log. Here’s my function:

function logit($text) {
    $now=date('Y-m-d h:m:s');
    $debugdata=debug_backtrace();
    $out=$now.' '.$_SERVER['SERVER_NAME'].' '.$_SERVER['PHP_SELF'].' '.$debugdata[2]['function'].' '.$text;
    file_put_contents('debug.log',$out,FILE_APPEND);
}

With this function, debugging is as easy as calling your logit() function instead of using print. I typically open another window and execute a tail -f debug.log to maintain a constant view of streamed debug data.

Tip 2 – Centralize your Database Updates

Creating a single reusable function to update your database can save your years of debugging.  It also provides a single place where you can add logging features to your updates.  For example, let’s say you want to create an update_log table for the database your updating.  This table will contain a record of every column, row and table that you’ve updated along with the mechanism used to update it and the date/time it was updated.

If you’ve got your mysql_query code scattered about your project, you’re going to need to add this logic all over the place.  If you’ve centralized your updates into a single function, you merely need to add the update_log logic to your update function.

Tip 3 – Borrow Heavily but Don’t Be A Script-Kiddie

We all do it.  Why re-invent the wheel, right?  I’m referring to the common practice of code-theft.  There are copious examples of many of the required components of most application challenges you’ll come up against.  So why not?  Why not, simply grab the code and slap it into your project?

It makes perfect sense – but you need to understand the code you’re lifting if your project is going to be a successful and supportable one.

A good friend of mine introduced me to a term over 12 years go – Script-kiddie.  A Script-Kiddie is a derogatory term used to describe someone that steals scripts or code, uses them but never fully understands how they work or in some cases, what they even do.  The term is typically used in a security context.

Simply put, don’t be one.

Tip 4 – Buy a Book (or two)

There are great books out there to help you with the PHP/MySQL/ExtJS development paradigm.  Here are a few that I own:

  1. Learning Ext JS
  2. Professional JavaScript Frameworks: Prototype,YUI, ExtJS, Dojo and MooTools (Wrox Programmer to Programmer)
  3. Learning PHP, MySQL, and JavaScript: A Step-By-Step Guide to Creating Dynamic Websites (Animal Guide)
  4. PHP and MySQL Web Development (4th Edition)
  5. PHP Phrasebook
  6. JavaScript: The Definitive Guide
  7. MySQL (4th Edition)

And here’s one that’s not fully released – but looks to be pretty awesome:

Tip 5 – Use FireBug

Firebug is a fantastic FireFox browser extension that enables you to inspect HTML and javascript, and even modify style and layout in real-time. I simply can’t imagine developing javascript, HTML or CSS based solutions without it.

Here’s a good screencast which explains the basics of getting, installing and using Firebug.

This assumes you can use the fabulous FireFox browser. In some cases, you can’t. For instance – my employer does not permit use of FireFox. In those cases, you can use IE addons to accomplish a minimal amount of the same capabilities as Firebug. Another option is to leverage the ExtJS Debug Console.

Tip 6 – Modularize Your Javascript

The ExtJS development paradigm is one that lends itself to rapid production. You’re madly cutting/pasting or typing in your component syntax and you’re application begins to take on a beautiful life of its own. It’s very easy to simply keep slapping components into your main javascript file, testing, debugging, and slapping more code on. I’m guilty. My first ExtJS application has over 4300 lines in a single javascript file… ugh… I’m embarrassed. Don’t get me wrong – the app works… it’s just nearly impossible to debug.

One way to implement modular code is to leverage iframes. The managed iframe user extension makes this very easy to do. Saki’s Example Page makes use of this extension beautifully. The code to create the main viewport and the layout panels is in one javascript file, but when you click on a link in the navigation tree, the code for the main or center panel is included in an iframe. This permits you to create one main application.js file and another separate javascript code file for each of the options in your tree.

Tip 7 – Use extjs-debug-all.js and extjs-debug-base.js During Development

To use the ExtJS Framework, you simply include the basic Javascript libraries and CSS stylesheet information in your HTML document. Here’s an example:



        Application Title
        
        
        
        




Tip 8 – Check for Trailing Comma’s

IE is much more picky about trailing comma’s than Firefox or Safari. Since I develop on a Mac, I’m forever missing trailing comma’s. I have an ancient laptop running Windows XP that I keep around for the sole purpose of testing apps in IE. Because javascript is interpreted, not compiled, you don’t get that piece of mind that comes from passing your work through the compiler before placing it in front of the user.

9 times out of 10 when I have an error in IE, it’s because of a trailing comma. ExtJS uses objects configured using JSON like syntax. Here’s an example:

var myExample = function() {
    return {
        foo: 'bar',
        boo: 'far'
    }
};

In this example myExample is an object which is configured with a function. The function in turn is configured with a return object which has parameters foo and boo. The syntax for this example is correct. Consider, on the other hand, this example:

var myExample = function() {
    return {
        foo: 'bar',
        boo: 'far',
    }
};

See the difference? That one minor, trailing comma after boo: ‘far’ will cause IE to stop interpretation of the entire javascript.

One way to catch this error is to copy and paste the source code of your javascript into JSLINT.

JSLINT will return the following:

Error:

Problem at line 4 character 19: Extra comma.

boo: ‘far’,

Problem at line 5 character 6: Missing semicolon.

}

Tip 9 – Create an Automated Backup Routine for Nightly Backups

There’s nothing worse than after weeks of steady positive progress, you suddenly find yourself unable to figure out what you’ve done to break things. Having a nightly backup strategy can provide valuable insight into the path you took to get where you are now.

For nearly every large scale project, I create a simple script to backup the code and data and ship it offsite somewhere – typically back home to my home development lab.

If you’re able to create a public/private key pair and configure passwordless login between your development environment and your home machine, you can create a simple script which can be executed automatically via cron to securely copy your development work back down to your home machine.

Here’s a link to creating a secure passwordless login scheme with SSH.

Once you have that in place, here’s a little script that you can customize to create backups for your work.

#!/bin/sh
# mlynn - standard backup script
# ----- - Remember to implement passwordless ssh
#
# Modify these variables
LOCALDIR=/Users/mlynn/Projects/WSS
REMOTEDIR=/var/www/vhosts/mlynn/httpdocs/wss/payroll/v2
LOCALEXTDIR=/Users/mlynn/www/extjs
HOST=your remote hostname.com
USER=your remote username
DATE=`date "+%m%d%Y"`
#
cd $LOCALDIR
mkdir -p backups/$DATE/v2
cd backups/$DATE/v2
scp -r ${USER}@${HOST}:${REMOTEDIR}/*.html .
scp -r ${USER}@${HOST}:${REMOTEDIR}/*.php .
scp -r ${USER}@${HOST}:${REMOTEDIR}/*.json .
scp -r ${USER}@${HOST}:${REMOTEDIR}/js .
scp -r ${USER}@${HOST}:${REMOTEDIR}/includes .
scp -r ${USER}@${HOST}:${REMOTEDIR}/images .
scp -r ${USER}@${HOST}:${REMOTEDIR}/css .
# Add additional directories or files that you want to capture
#
# This line links your local extjs directory so you don't have to download nightly
ln -s $LOCALEXTDIRs .

This will create a fully functional copy of your web development area on your local machine. The last line of that script creates a symbolic link to the ExtJS library directory on your local machine. This assumes that you don’t want to copy down the extjs javascript library distribution every night.

Make sure you modify the following variables to customize the script for use on your local machine.

LOCALDIR – this is the local directory on your home development machine.
REMOTEDIR – this is the root directory of your development work on your client or remote machine.
LOCALEXTDIR – this is the full path to the extjs libraries on your local machine.

Once you’ve got all that setup – add your script to cron to kick it off nightly (or even more frequently.)

Tip 10 – Visit ExtJS.com Often

ExtJS.com is frequently updated with new versions, featured implementations and blog posts designed to simplify use of this great framework.

The site is well organized and has several sections specifically designed to help you getting started using the framework. The Learn section is a great place to start.

Bonus Tip – Use an Alert Service To Notify You of Updates on ExtJS.com

Since timely information is very valuable when you’re working on a project with tight deadlines, you may consider using an alerting service to tell you when new information has been added to the extjs.com site. http://www.changedetect.com is one option that offers a free web site modification alerting service.