My Own Private Brochure Page
Before you start rolling your eyes, I'm completely aware of my lack of design skills, and this is not meant to be something that you implement without adjustment. While this isn't going to look like something you want to have on your site, the underlying code and methods used to render the content can provide the groundwork for a completely re-imagined program brochure page.
I took on this project as a way to familiarize myself in working with the public interface API's data. Specifically, the data associated with the program brochure page, and while I don't have the design chops to really produce something eye-popping, I can definitely implement a few alternate interface ideas that are not used by the built-in brochure page.
The goal was to put together a template that separates the design/presentation layer of the brochure page from the code that fetches and parses the resulting data. It was not completely successful, but it gets pretty close.
There are a few files involved although only one of them is actually code; the other two are templates that are used in the implementation. The code file is long and complex, but I've put in a lot of comments that try to make it as clear what the code is doing (no matter how strangely).
Implementation instructions
There are a four steps to using this template:
1.) Download the code files and save them to your document center
There are three template files involved:
CustomBrochurePageCode.html
CustomBrochurePageBrochureTemplate.html
CustomBrochurePageBannerTemplate.jpg
The first is an HTML document with the styles, containers, and script that will generate the brochure page (CustomBrochurePageCode.html). The second is the html that should be used in the program brochures as the template (CustomBrochurePageBrochureTemplate.html). The third is a jpg that can be used as a template for the banner images that you want to create (CustomBrochurePageBannerTemplate.jpg).
All three of these files are in the github.com repository. Unlike other HTML documents that I've posted here that you store in the document center, these need to have their content copy/pasted into the source HTML of the WYSIWYG Editor. They aren't designed to be saved and fetched as files. When you're done, you should have these items appearing in your document center like this:
2.) Create banner images and put those IDs in the program notes of your programs
If you want to have different brochure banner images for different programs, you can use the template in a standard image editor and save different images with different dimensions. However, it would be a good idea to keep the width of the images consistent. I'd recommend creating a folder in your image library where you store these:
You'll be taking the image ID#s of each of the banners and then implementing them in your programs by adding |BannerImage|#| to the program notes with the image's ID# where the '#' is. So, for example, if I had banner image that was image ID#2447 in my image library, I'd have program notes that look like this:
3.) Use the brochure template to create tabbed brochure content
Now you're ready to create the brochure content for the page using the file in the document center (CustomBrochurePageBrochureTemplate.html). You'll need to copy/paste the raw html of that template into the program's WYSIWYG Editor on the brochure tab. Then you can change the lorem ipsum text of each section to what you want it to display on that particular tab.
This would be great time to implement another trick of mine - One Click Brochure Templates.
When viewing this template in the WYSIWYG Editor, it will just appear as one long piece of content, but it has the necessary markup included so that the styles and scripts can do their thing to turn it into tabbed content. Don't worry that it looks like this in the program builder:
4.) Preview the alternate brochure page
At this point, you're ready to view your program brochure in the new template. All you need to do is get the document center file ID# of 'CustomBrochurePageCode.html' and the program ID# of one of the programs that you've configured to go to the new brochure page. Then, navigate to this URL:
http://{YOUR SITE'S DOMAIN NAME}/index.cfm?FuseAction=Abroad.ViewDocument&File_ID={FILE ID# OF CUSTOMBROCHUREPAGECODE}&Prog_ID={PROGRAM ID# OF THE PROGRAM YOU CONFIGURED}
You should see your brochure's content in the alternate format. If you don't, then you might need to check the browser's console log to investigate the cause of the problem.
This code is like the custom program search that uses the API. I've split the code into three distinct parts. The first section is the 'style' tag which is pretty self-explanatory. I've tried to maintain all formatting through CSS and nowhere in the container code itself. I still resorted to using the 'center' tag in one spot of the markup, but other than that, you should be able to adjust the fonts, lists, and buttons completely within the style section. The second section is the actual markup which has the containers that will be filled and revealed by the script. What makes it more than a bunch of empty 'divs' is that I've included the standard 'tips section' of a StudioAbroad page. It's just a copy of what you would get on any other brochure page except that I modified the tips to explain how the content is being fetched and rendered.
The real meat of the code is the last section; the script itself. This has all functions that are used to build the brochure page using the API.
$(document).ready(function(){
This is the initialization function of the script, and all it does is look in the page's URL for the parameter that tells it which program's data to fetch. Then, it executes the API call using the program ID# that it found in the URL.
That's it ... Everything else happens when this executes ...
function _cb_processBrochure(data) {
This is the callback function that is run when the API call succeeds and gets back a JSON object with all the program's data in it. Like the initialization function, it's pretty simple and fires off a bunch of function calls for each section of the brochure page.
However, there is also a section that I've got commented out which can be reinstated if you want to have the data packet that the API is sending logged into the browser's console. This is a really useful way to directly inspect the data you're getting back from the API, and I used it prodigiously when building this script and running tests in my browser.
function actionPanel(data) {
This function is called to build the 'Apply Now' and 'Request Advising' buttons in the 'Action Panel'. Unlike the standard brochure pages, none of the text of this custom page is driven through the text interface editor. If you've renamed a section of button on the brochure page, you'll need to re-implement that adjustment in the specific section of the script where that element is built.
There are two related functions just after this function that builds the buttons.
function RequestAdv() {
function ApplyNow(desturl) {
These are the functions that are called whenever an 'Apply Now' or 'Request Advising' button is clicked. They are copied code from the standard brochure page. If you want to adjust the behavior of the page when someone clicks on these buttons, you can adjust that in these sections of the script.
function bannerBuilder(data) {
This function creates the banner image. It also adds the name of the program and, if there is one, the sponsor as well. I have to admit, that it definitely is a little bit of a hack to embed the image ID into the program notes and parse through them like that, but a more elegant method of doing it (like a program parameter value) would involve configuration in the script itself, and I wanted to make this code 'plug-and-play' since it is really intended as more of a proof of concept rather than production-ready code.
Something to note about the banner is that it uses CSS to position the name of the program and sponsor over the banner image rather than forcing the person building the banner to have the text as a part of the image itself. It also ensures the program name displays when there is no banner image.
function informationPanel(data) {
This function builds the information panel with the program's parameter option values, terms, and locations. It's a very complex bit of code, but here's the outline of what it is doing:
- Look for the existence of data for a section (parameters/terms/locations)
- If there is data, parse through it and dump it all into an array
- If there is data in the array, loop through it and build the html of that data
- After going through all the sections, build the navigation options that are needed
- Dump all that html into the panel and set up event handlers on the navigation tabs
Now, you might notice that I'm actually writing quite a bit more code than I really need to. If I was being clever, I would combine steps two and three and just build the html itself as I parse through the returned data rather than dumping it all into an array first, but by doing it the way I did, it makes it easier to update the code that builds the html without worrying about mucking up the data itself. So, for example, suppose I wanted to have the locations displayed as markers on a Google-rendered map rather than as a boring list. I know exactly where in the code to make that change, and I don't need to work around all the logic that is parsing through the returned data.
function showInfoPanel(whichone) {
This function is the event handler for the tabs in the information panel. I'm sure I could have unified the functions that are used by the information panel and the brochure panel and just had a single function determine what needs to be updated, but this keeps the code for one panel all in one place and the code for the other panel in its own place.
The code itself is pretty straightforward though, and it's a technique I use quite a bit for client-side navigation. I hide everything and then just reveal what was clicked.
function brochureTabs(data) {
This function is a bit of a monster. It is parsing through all the brochure content as well as the dates, budget, and course information in the data returned. It's like the function that builds the information panel but with much more complex data.
It does it the same way though; stuff all the data into an array and then iterate through that array to build the html that you want to add to the page. Finish up by building the navigation tabs and add it all into the page's container.
The most complex of the structures are the program date records because they deal with start and end date data that might or might not be there. What made the dates especially difficult was the javascript object for dates. Firefox is remarkably picky about how you create them. Our API's formatting doesn't make it simple either.
function showBrochurePanel(whichone) {
This is the event handler for clicks on the brochure's tabs. Like I mentioned earlier, it could have been folded into the information panel's function. It's basically doing the exact same thing, and that makes it a real candidate for being refactored should I ever return to this code and update it.
When someone selects a term from the budget sheet drop-down menu, this is the function that is called to get the budget sheet's information and add it to the page. It's actually a bit of a cheat.
The public interface API doesn't provide you with budget sheet data. All it gives you is a URL to the program's public budget sheet page for each term for which there is a published budget sheet. I'm leveraging jQuery's ability to run an AJAX call to fetch the HTML of a section of a destination URL and dump it into a container on the page. Lucky for us, on the public budget sheet pages, there is just one section with the class 'data-table' assigned to it, and it just happens to be the budget sheet table.
function reformatdate(datestring) {
This is a quick little helper function I built to deal with the way that Firefox interprets date objects. I'm actually a bit suspicious about the code around the dates. I wrote it so that it would sort the dates with the earliest application deadline at the top and the latest at the bottom.
I think that's just naturally how the dates are sent back by the API. It's possible I'm just really overworking the date details and could have gotten away with some way-way-way simpler code, but I'd like to think that my routines are less likely to break.
... unless you change the date mask your site uses...
Yeah... I'm pretty sure that will break it.
Adjusting the CSS of this page's code will definitely allow you to manipulate the fonts, buttons, and colors, but chances are that you are going to want to come up with a completely different and original design.
When I started out on this project, I just scribbled a bunch of panels on a piece of paper and started labeling what I wanted to appear in them. If I had a professional graphic designer at my beck and call, I would have then handed my scribbles over to them along with the URL of the site and told them to come up with cool, concept designs based on my really awful wireframe.
Unfortunately, I don't have such a resource available that would do professional work like that in return for a "I'll be your best friend". So I just leaned on the pre-existing interface elements that are in the Terra Dotta Software CSS (specifically the widget classes). Good enough for a proof of concept, right?
So this example's CSS is pretty straightforward, there aren't too many classes and ids, but for example, if I wanted to change around the look and feel of the tabs that you click on to switch from one section to another, I'd change around this section of the style block:
.section-tab {
border-style: solid;
border-width: 1px 2px 2px 2px;
display: inline;
padding: 3px 10px;
margin: 5px;
border-radius: 0px 0px 10px 10px;
font-family: Arial;
font-weight: bold;
background-color: #1372a8;
color: white;
border-color: black;
}
.selected-section-tab {
box-shadow: 0px 1px 10px -1px #000000;
background-color: #000000;
}
I could adjust the color of the tab to match my widget's header color by adjusting the 'background-color' attribute, or I could change the font, color of the text, how big the tabs are, etc.
Changing around the actual position of each widget would involve me changing around both the 'div' tags that are used as their containers in the content section as well as the CSS for those containers. This could get a bit trickier as you might need to learn a few pointers about positioning elements on a page. If you want to get into that level of detail, I'd suggest searching for some pages that explain positioning through CSS; specifically, the difference between block and inline elements and how to work with them to get things to appear exactly where you want them.
One thing I would definitely encourage when customizing the display of a template like this is to always look at the CSS before trying to put tags and attributes in the brochure container that will impact how the content looks. It's considered good practice in general because it will keep all the code that effects the 'presentation' of your content in one place, and the structure of how you are organizing it in another place. If you need to tweak it or make changes at a later time, it is much easier to look at code organized in this manner and update it.
Now, as long as we're talking about 'good practice', a real brochure template would be three separate files. One for the CSS, another for the script, and a third for the HTML which would link to the other two. It would allow the CSS and script to be cached by the browser and only reloaded when necessary. If you have full access to your server, that might be an option, but in cases where this level of access isn't provided (like Terra Dotta hosting), as long as you aren't getting too heavy on the size of the file, putting it all in one place isn't going to be a major performance issue.
The big final aspect of this is that once you've got a beautiful template you want to deploy, how do you switch a site over to use that template rather than the software's built-in brochure page?
There are a few methods to direct users to the alternate brochure page URL, and I won't go completely into the technical details because there may be different wrinkles in how you decide you want to do it.
The first would be to use what is referred to as a 'stub-override' for the program brochure page. This involves making a change on the server itself. There is a file in the code called '_stub.cfm' and is used to put in high-level code that runs whenever a page is requested. In this case, you would have code that checks the URL of the page being requested and if it's requesting 'index.cfm?FuseAction=Programs.ViewProgram&Program_ID=', you redirect to the alternate URL with that program ID as the parameter in it. This involves needed to learn a little bit of the ColdFusion Markup Language (CFML), and it also assumes you have direct access to the server and the stub file ... which, if you are hosted by Terra Dotta, you do not.
A second method involves putting a script into the program brochure tips text that would grab the program ID out of the page's URL and then auto-redirect the user to the alternate URL with that program ID. This would be a case where you wouldn't actually want to use the '$(document).ready(function(){' jquery command in the script because you would want to redirect the user immediately, not after the page's content was ready. This method can be done by anyone that can put scripts in the text interface, but it seems a little bit janky to me because you're still 'loading' the old brochure page.
The third method that could be used would be to put a script on the program listing and search result pages that uses a jQuery command to find all links to the program brochure page and change their 'href' attribute to the new URL with the proper program ID# in it. It wouldn't be an overly complex script to write, and it would also make it easy to add conditional checks as well. You could test out the new template on a sub-set of users by making the script only switch the URLs when the user has a specific cookie value and then provide a link to a page where the testing users could set that cookie in their browser.
A final method would just be to completely re-write your program search, listing, and search result pages using the public interface API and use the alternate brochure page URL instead of the standard one. This would be a bit more of a project to embark on, but let's be honest here, you've already decided to completely re-write the program brochure page using javascript. Why not rewrite the whole program discovery interface as well?
This has been tested in Version 12.