Start and stop ColdFusion localhost with .bat files (Windows)

Here's a simple trick that saves a few clicks. If you are running a ColdFusion local server on a windows PC, you can start and stop the CF service with a simple bat file.

Make a new text file on your hard drive somewhere (i keep mine right on the desktop), and name it "cfstart.bat" - in your text editor of choice, enter this one line and save the file:

    NET START "coldfusion 9 application server"

(with the quotes, just like that)

You can make another called "cfstop.bat" and, you guessed it, 

    NET STOP "coldfusion 9 application server"

To use the files, on my Windows 7 PC, I just right click and select "Run as administrator", and the service stops or starts up right away. Now instead of running all the time, consuming memory, CF only runs on my local machine when i need it. 

Note: you may also want to remove the ColdFusion service from the list of items that run on startup - use start > run > mscofig to see the list.

 

 

Mura CMS / CKeditor paste as plain text by default

Any developer who uses a CMS with a wysiwyg text editor knows the frustrations of clients pasting content from MS Word and other word processing programs directly into the editor, complete with unwanted styles, and even markup elements, causing all sorts of problems on our otherwise perfectly-formatted pages.

Mura CMS uses the ubiquitous CKeditor (formerly FCK) with a number of features enabled by default, including a "Paste as Plain Text" button. If clients remembered to use this, we would be all set. But, they don't.

Fortunately, there's an easy one-line fix.
Just open up [siteid]\includes\themes\[theme]\js\editor\styles.js

and paste in this line

CKEDITOR.config.forcePasteAsPlainText = true;

That's it. All pasting of content should now be clean, with extra styles and markup removed, just as if you had clicked "paste as plain text" in the editor toolbar. 

Adding Navigation Items to MuraCMS Admin

Here's a quick and easy enhancement you can make to the MuraCMS admin, adding links in the top-level navigation for quick and easy shortcuts to commonly-used sections of Site Manager.

Like so many things in Mura, the hooks already exist for this functionality, you just need to know what to put where. In this case, it is quite simple.

1. First, open up [siteid]/includes/eventhandler.cfc

2. Find the opening line <cfcomponent extends="mura.cfobject">, and paste these lines below it:

<cffunction name="onAdminModuleNav"> <cfargument name="event" /> <cfset var newLinks = ''> <cfsavecontent variable="newLinks"> <li><a href="index.cfm?fuseaction=cArch.list&siteid=... [shortened]">Blog Entries</a></li> <li><a href="index.cfm?fuseaction=cArch.list&siteid=... [shortened]">Photo Gallery</a></li> </cfsavecontent> <cfreturn newLinks /> </cffunction>

3. Change the <li><a> markup as needed, to insert the new links you want to create.
(In my examples above, I just copied the full URL from the admin view I wanted to link to.
There is probably a better way, dynamically generating the admin link by filename, but this works just fine, if your contentIDs stay intact.)

4. Save and upload the eventhandler.cfc, and reload the Mura application from within the admin - you should see the new links appear in your menu.

 

Some official Mura resources: 
http://docs.getmura.com/index.cfm/developer-guides/back-end-development/mapping-events-in-mura/

http://docs.getmura.com/developer-guides/back-end-development/plugins-event

Finding Available Mura CMS Content with getAllValues()

One of the first things I wanted to know as I started working with Mura CMS templates, is how I can dump out all the available variables.

I'm used to the versatility of CFML's CFdump tag, outputting the contents of any query or other CF object to the page for easy reading and reference as I wire up the css and html to display the dynamic content. In Mura, where everything is returned by a 'bean' via specifically named CF functions, cfdump doesn't always have the expected results.

For example, in a content-driven page in mura, dumping out #$.content()# will show the methods available, but not the actual values they'll return for the page you're working on.

In comes another Mura one-liner "getAllValues()". This can be attached to almost any Mura root-level object, to show all the values available, just as if you were dumping out the results of a single cfquery record, struct or nested array.

So, to get all the available goodies for a standard page or content-based item, simply add the getAllValues() function at the end of your cfdump:


<cfdump var="#$.content().getAllValues()#">

This also works for other Mura beans, such as a Mura feed:


<cfdump var="#variables.feedBean.getAllValues()#">

or any record being parsed by Mura's "iterator":


<cfdump var="#arguments.item.getAllValues()#">

or even the content of another page, by ID:


<cfdump var="#application.contentManager.getActiveContent('[content id]', '[site id]').getAllValues()#">

or by filename (the filename is the name of the content-node, same as seen in url):


<cfdump var="#application.contentManager.getActiveContentByFilename('[filename]', '[siteid]').getAllValues()#">

As I understand it, most of these values are directly available via the CF request scope, but dumping out #request# in mura is huge, and takes a while to dig through. GetAllValues() is the one you want.

The Mura Docs list a number of methods for getting content via the Mura API. I believe the getAllValues() method can be used with all of the 'read' functions.

Persist form values on reload w/ jQuery & ColdFusion

A designer friend presented me with a somewhatlong and complicated HTML form. It is a survey/contest entry for employees of a specific industry, with dozens of fields which include regular text inputs, text areas, and radio buttons.

My task is to create a routine to submit this form via e-mail and store the contents in the database. ColdFusion makes that easy with the built-in #form# scope. And for validation, I simply made his HTML < form > into a <cfform>, and all of the <input> and < textarea > elements into <cfinput> and <cftextarea>, adding 'required="true"' and a validation rule and/or message for each. Whipping up a quick server-side validation for the required fields was also a snap with CF.

Then it occurred to me - if there is in fact some error with the user submission, we will return the user to the form showing an error message at the top of the page.

However, unless we somehow persist the values that were entered, the form will be blank, and the user will no doubt be a little frustrated. This is a long form!

one method would be to create <cfparam> values for each element in the form, and then give each input the a value like value='#form.thisFieldName#" - that's common practice, and works great, but I don't want to do the tedious work. Also, I will be passing this form back to the designer, and don't want him to have to create the default value if he decides to change the names of any inputs, or at other input to the form.

So, I came up with this.

Assuming you already have jQuery in your page, this little block of code will loop through all of the posted values in the ColdFusion form scope, then, using jQuery, will assign the given value to any form element with a matching "name" attribute, allowing us to easily re-populate all the form fields in the page, in one fell swoop with javascript.

Since i only had input / textarea / select / radio button inputs, this just handles those types, but could easily be ammended to include checkboxes and more.

<!--- if form scope exists --->
<cfif isDefined('form.fieldnames')>
    <cfsavecontent variable="hcode">
    <script type="text/javascript">
    $(document).ready(function(){
    <cfloop list="#form.fieldNames#" index="ff">
    <cfset rawVal = form[ff]>
    <cfset ffVal = jsStringFormat(form[ff])>
    <cfoutput>
    $('input[type="text"][name="#lcase(ff)#"]').val('#ffval#');
    $('select[name="#lcase(ff)#"]').val('#ffval#');
    $('textarea[name="#lcase(ff)#"]').text('#ffval#');
    $('input[type="radio"][name="#lcase(ff)#"][value="#rawval#"]').attr('checked','checked');
    </cfoutput>
    </cfloop>
    //end jQuery
    });
    </script>
    </cfsavecontent>
<cfhtmlhead text="#hcode#">
</cfif>


Yes, this makes a big long looped jQuery script in the head of the user's page. But in this instance, it is working perfectly, with no noticeable slowing of page load, or other drawbacks that i can see.

Filtering content in Mura CMS

In my ongoing adventures w/ Mura ColdFusion CMS , I have been setting up a calendar of events for a local tourism website.  A 'calendar' is a built in content type in Mura, with many options for showing and filtering the content.

For this calendar, we want our events to show up as soon as they are entered, remain on the site until 2 days after the event date has passed , and then be removed from view. So, we need a filter that compares the current date to a date two days in the future - easy with ColdFusion's dateAdd() function, but the trick was getting that function into the Mura "filter" settings.

Here's how I set it up:

1) create the calendar

- in site manager, click the "+" next to home page (or wherever) and choose 'add calendar'

- give your calendar a title, and click 'publish' (other details can be added as desired)

2) create the "content collection" to show the calendar's info

- click 'content collections' , then select 'add new Local Index'

- give it a name

-  next to the heading "Choose content from section:", click the (less than obvious) "[select section]" link , and type in part of the name of your calendar to search for that content**

- in the search results, click the "+" on the far right to add your calendar, making sure "include features only" is set to "no"

** this has been one of the key Mura admin concepts I've had to adjust to - this type of content search is used a lot in the admin, rather than dropdowns or other standard ways of presenting existing selections. It works well once you get used to it.

3) set up the filtering

- on the "advanced filters" tab, add two filters, with the following selections:

i) Start Date / Time : Greater Than or Equal To : [mura]dateAdd('d',2,now())[/mura]

ii) Or : Stop Date / Time : Greater Than or Equal To : [mura]dateAdd('d',2,now())[/mura]

The key was the use of The Mura Tag , which allows you to use any standard CF functions in place of a static value ( documentation here ) - in this usage, we are comparing today's date to a date 2 days from now (if you wanted to be more specific you could add 48 hours instead of 2 days ... or anything you like )

As I am quickly learning, Mura contains a number of filtering options for its content collections. I'm interested in seeing your examples if you've got 'em!

 

How to set up local vs. production settings for Mura CMS

In an effort to become acquainted with Mura CMS, I have been spending some time looking at the overall way the application is structured - what is included into what, where settings are stored or specified, and what the options are for modifying the default way things are done, in order to retain some of the in-house workflow concepts I have developed over the years.

One of the main aspects of my production workflow involves the easy use of both a local and live server, running from the same database. Generally, when starting a new ColdFusion project, I like to:

- Set up a local directory for the project, where i can work in the browser via a local host url
(something like http://172.16.17.5:8500/SiteName/wwwroot/  or http://localhost:8500/sitename/wwwroot )

- Set up a database on my live production server at www.GoWestHosting.com

- Create a DSN on the live server, pointing to the database

- Create a DSN on my local CF server, pointing to the same remote database

Now I can work locally and view my changes instantly without the need for FTP.

Or, as needed, I can push changes to the live site with a few clicks, and view the changes there as well (such as posting work for clients, or working with routines that require server-specific settings, launched from the site's "real" location)

My application.cfc contains both sets of DSN info, and uses a switch, based on the current cgi. server variables , to determine which DSN to run from, along with other server specific settings (such as google map key). So, wherever the site is viewed, my application 'knows' which content paths and other settings to use for each page request or query.

(So... what about MuraCMS?)

One of the first things I noticed when installing Mura locally was the way that it cached the local directory structure. So if my Mura site was installed in a subdirectory of the local site, e.g. http://localhost:8500/sitename/wwwroot/test/ , Mura would store the setting "/sitename/wwwroot/test" automatically, and prepend this path to all required assets. Wonderful. Superb. But...

Then I pushed the Mura files to the live server, uploading the works via FTP. And found I had a problem. That path was still being prepended to all assets... but didn't exist.
On the live server i was simply working from http://sitename.com/test/ , so everything was instantly broken - images, javascript, css.

Unlike my own usual practices, where all primary templates or pages live in the site root,  Mura is designed to use 'root relative' paths, rather than location relative, which makes sense if content will be served from different directory levels.

So instead of simply looking in ../css/ for a css file, it wants to use the path /sitename/wwwroot/test/css

(So... how did I fix this? Get to the point already... )

Half of any solution is identifying the problem. In this case, I needed to find out "how to use two different sets of configuration variables" , and set out to find the answer.

On setup, mura creates and populates a file called 'settings.ini.cfm', which is a simple text file with variables and values stored one per line. And inside, I could see the paths were being stored as text strings. Cool. Now I know where it lives... but how to change it on the fly, and keep two different versions?

I asked my question to the very friendly, patient guys on the Mura Show , but must not have asked correctly, or clearly enough. I came away thinking the solution was to set up a domain 'alias' and somehow map a direct IP to my subfolder locally , which doesn't work since you can't put paths in the Windows hosts file... and i got into a right frustrating mess.

Deciding to take another crack at it with fresh morning-coffee eyes, I got smart and did a bit of googling. And I found this, the settings.ini reference from the Mura site: http://docs.getmura.com/index.cfm/installation-set-up/settingsinicfm-reference/

and... AHA! a classic RTFM moment.

(finally... the fix !)

wouldn't you know it, the very first line of the settings.ini.cfm file is for the "mode", (which i completely overlooked before, and the Mura team must not have thought of in reference to my seemingly vague questions. )

The default mode is 'production' and beyond the first few lines, all settings in the file are under a heading of [production]. The light started coming on right about now... they really did think of everything!

So, all I had to do was create another grouping, and change that master 'mode' setting. I simply duplicated all the lines below [production], added a new heading of [localdev] , and changed the settings to match those of my local server. (I also changed 'production' paths to match the settings of my live production server with the simpler root directory structure)

Just a few more steps - upload the changed file to the live server, and click 'reload application' in the Mura admin.  Then, change my local copy of the settings.ini.cfm file to 'mode=localdev' , and click 'reload application' in my local admin as well.

This caused the local settings to be loaded for the local site, and the production settings to be loaded for the production site ... and i am back in business, working in both locations with ease!

Bearing in mind that any uploaded images will need to be manually copied with FTP, and some other things might need a little hand-holding, I am very pleased to be back in business with the freedom to work the way I am used to, with live, functioning copies of the complete site on both my local server and the live location.

The only caveat at this stage - I'll have to be careful not to upload the settings.ini.cfm file, since I still don't have an 'automatic' switch for which group of settings to use. But as long as my production version of the file says "mode=production" and my local file says "mode=localdev" , I should be good to go.

 

HTML Formatter ColdFusion-friendly code cleanup tool

No matter how clean your code, there's something to be said for a fast, clean pre-launch cleanup with a reliable code formatter . My favorite by far is the HTML Formatter from LogicHammer.com:  http://www.logichammer.com/html-formatter/

Complete with a full set of ColdFusion-friendly options, this simple tool makes cleaning your code a snap. I use it as I'm working, to clean up the work-so-far at any point, and before final launch to make sure the production code will be as easy as possible to maintain and revisit later on. It is a standalone executable, which means there's no installation, and you can put in anywhere you like on your hard drive.

I simply create a taskbar shortcut on my Windows PC and drag the files I want to clean directly from the 'project' view in Eclipse onto the icon - couldn't be faster, simpler or easier. I prefer to have my original files altered, with the originals automatically put in a specified backup location - you can also assign the option to leave the original alone and create a cleaned-up copy.

Among other fav features, HTML Formatter ships with a simple text-based config file which makes it incredibly easy to specify tags to ignore or to indent, and file extensions to be formatted or skipped ( you can run the formatting on specific files, or an entire directory).

For only $14.99 you get all the features and 2 years of updates (there is also an 8.99 version with a basic feature set). The program's developer has answered every question I ask directly and has been very helpful with customizations, even building in some features I requested a while back (for the record - I'm not affiliated with logichammer in any way, just very pleased with this slick little tool).

How to find lowercase (no caps) values in mySQL (and Capitalize them with ColdFusion)

I have a request from a client to help clean up some customer-entered data in a mySQL database, specifically, we need to capitalize all of the values in a column called 'user_city'

For the actual capitalization, I am using the very handy CapFirstTitle() function from CFlib : http://www.cflib.org/index.cfm?event=page.udfbyid&udfid=116

But first, I need to find all of the entries that are not already capitalized. This dataset has tens of thousands of records , including some with a blank value in the 'city' field - no need to loop all of that just to fix our caps!

So, here's the SQL query code to find all of the records with no capital letters at all, by comparing to a lower() all lowercase version of the same value:


SELECT user_city, ID
FROM site_users
WHERE user_city = lower(user_city)
AND NOT user_city = ''
ORDER by user_city

And here is the full CFoutput / CFquery code for the loop and update with Coldfusion, and the CapFirstTitle() function in the head of the page:


<cfoutput query="myQueryAbove">
    <cfquery datasource="#application.dsn#">
    UPDATE site_users
    SET user_city = '#capFirstTitle(myQueryAbove.user_city)#'
    WHERE ID = #myQueryAbove.ID#
    </cfquery>
</cfoutput>

for other columns you could use OR in the first query and an additional statement in the second, or just change the queries, run the page again, or even, make the column name a variable and just change it once in the head of the page... easy.

Show any Twitter Feed on your site with ColdFusion and CFFEED

This is so simple, I'll let the comments do the 'splainin:



<!---
start CF Twitter Feed
--->


<!--- SET THE URL: add your username instead of mine --->

<cfset feedurl="http://search.twitter.com/search.atom?q=from%3Agowestweb" />

<!--- CFFEED does all the work --->

<cffeed
source="#feedurl#"
properties="feedmeta"
query="feeditems"
overwrite="true" />


<!--- CFOUTPUT shows the feed like a query --->

<ul class="tweet">
<!--- change maxrows to suit your layout --->
<cfoutput query="feeditems" maxrows="3">
<li>#content#</li>
</cfoutput>
</ul>

<!---
end CF Twitter Feed
--->


<!---
NOTE: in addition to #content#, you can show date and other columns related to each feed item.
Use <cfdump var="#feeditems#"> to see all the available columns in the query
--->



ColdFusion Form Spam Prevention: CF Meetup Notes and Follow-Up

Thanks to all who attended my first CF Meetup presentation.

Info: http://www.meetup.com/coldfusionmeetup/calendar/11596049/?a=nr1p_grp&rv=nr1p

Recording: http://www.meetup.com/coldfusionmeetup/pages/Recordings_of_the_ColdFusion_Meetup-2009/

Demo Page (as seen in the presentation): http://www.gowestwebdesign.com/demos/contact-form/index.cfm

As far as I can tell we had a good turnout, and though talking to a silent connection takes some getting used to, the live-chat comments and interaction during the talk really made it fun (and helped me fill the full time slot with this simple subject!).

I really enjoy meeting other developers and designers, and I hope anybody who attended, had questions or just wants to get more involved in the community will drop me an email, check out our web developer newsgroups (see the link top right of this blog), and of course... be my Facebook and/or Twitter friend.

Thanks also to Charlie Arehart for all of his efforts keeping the CF Meetups going, and growing strong. He was the perfect balance of aggressive and encouraging in getting me to present this topic, and I am very glad he persisted. He's definitely the right guy for the positing of CF Host and quickly removed any concerns or worries I might have had just before we went live.

Now that it is done, I would like to do another! On that note, if there is anything you think I know about, that you'd like to see me share, please do drop me a line.

Several people asked to have a copy of the code used in the presentation. The sample below is directly from the file shown in the demo.



<!--- START PROCESSING --->
<cfif isDefined('form.senderFrom')>

<!--- VALIDATE FIELDS --->

<!--- check email --->
<cfif NOT len(trim(form.senderFrom)) gt 6 or NOT isValid('email',form.senderFrom)>
<cfset request.formError = 'A valid email address must be provided'>

<!--- message --->
<cfelseif NOT len(trim(form.senderMessage))>
<cfset request.formError = 'Be sure to include a message'>

<!--- honeypot --->
<cfelseif len(trim(form.email_address))>
<cfset request.formError = 'Spam!! <br />(Run away! Run away!)'>
</cfif>

<!--- /end VALIDATE FIELDS --->

<!--- CHECK FOR UNWANTED CONTENT--->
<!--- loop all form variables --->
<cfloop index="f" list="#form.fieldnames#">
<!--- set variable for field value --->
<cfset value="#evaluate('form.#f#')#">

<!--- BANNED WORDS --->
<cfset bannedWordsList = "herring,albatross,dragon,grail,lumberjack">

<!--- loop the banned words list and see if we have a match --->
<!--- Check for banned words --->
<cfloop list="#bannedWordsList#" delimiters="," index="w">
<cfif FindNoCase(w,value)>

<cfset request.formerror="<br />Beg your pardon? <br />Your WHAT hurts?">

<cfbreak>
</cfif>
</cfloop>
<!--- / end BANNED WORDS --->

<!--- HTML BLOCK --->
<cfset leftChar = '<' >
<cfset rightChar = '>' >

<!--- look for both characters contained in our content --->
<cfif findNoCase(leftChar, value) AND findNoCase(rightChar, value)>
<cfset request.formerror = "Text only please - no HTML">
<cfbreak>
</cfif>
<!--- / end HTML BLOCK --->

</cfloop>
<!--- / end CHECK FOR UNWANTED CONTENT --->

<fieldset>
    <legend>
        <cfif isDefined('request.formerror') and len(trim(request.formerror))>
        Error!
            <cfelse>
        Thank You
        </cfif>
    </legend>

<!--- SHOW RESPONSE --->
<cfif isDefined('request.formerror') and len(trim(request.formerror))>
<p><strong>ERROR: <cfoutput>#request.formerror#</cfoutput></strong></p>
<p>Go <a href="javascript:history.back()">back</a> and try again</p>

<cfelse>
<p>Thank you. <br /><br />Your message has been sent and we will reply soon!</p>
</cfif>
<p> </p>
<p> </p>
<p> </p>
<p> </p>
<p> </p>
</fieldset>

<!--- IF FORM NOT SUBMITTED (show the form) --->
<cfelse>

<fieldset><legend>Sample Contact Form</legend>

<cfform name="contactForm" action="#cgi.SCRIPT_NAME#" method="post">
<div>
<label for="senderName">Name:  </label><cfinput type="text" name="senderName" size="48" value="" required="true" message="Your Name is required">
</div>
<div>
<label for="senderFrom">Email:  </label><cfinput type="text" name="senderFrom" size="48" value="" required="true" validate="email" message="Email Address is required">
</div>
<div>
<label for="senderPhone">Phone:  </label><input type="text" name="senderPhone" size="20" value="">
</div>
<div>
<label for="senderPhone">Your Message:</label><textarea name="senderMessage" cols="30" rows="12" style="width:310px;"></textarea>
</div>
<div style="text-align:center">
<input type="submit" value="Submit">
</div>

<div id="email_wrapper">
<input type="text" name="email_address" value="" size="20">
</div>

</cfform>

</fieldset>

</cfif>
<!--- / end IF FORM SUBMITTED --->

Thanks again to Charlie and everyone else - this has been a very positive and rewarding experience, and I hope to return with more good CF-Stuff to share.

More Entries

blogcfc 5.9.1.002 by raymond camden
contact michael evangelista