Wednesday, October 24, 2007
Thursday, October 18, 2007
SQL Server Script to Restore a Database from File
I frequently have to backup a database from the production machine and restore it in my testing environment. You can do this with SQL Server Enterprise Manager (or other similar tools) but it can get to be a pain if you have to it over and over again. So here is a script to the second part - restore a database from a file to sql server. For the first part, please see my related post called SQL Server Script to Backup a Database to File. To use this script you need to:
- Set the database name in the @databaseName variable to your database
- Set the @restoreDirectory variable to the absolute directory path where the database backup is found
- Run the script (with something like Query Analyzer)
Download the script from http://tech-cats.net/blog/downloads/sql/SQLServerRestoreDatabaseFromFile.txt
-----------------------------------------------------------------
-- Restore database from file
-----------------------------------------------------------------
use master
go
declare @backupFileName varchar(100), @restoreDirectory varchar(100),
@databaseDataFilename varchar(100), @databaseLogFilename varchar(100),
@databaseDataFile varchar(100), @databaseLogFile varchar(100),
@databaseName varchar(100), @execSql nvarchar(1000)
-- Set the name of the database to restore
set @databaseName = 'myDatabase'
-- Set the path to the directory containing the database backup
set @restoreDirectory = 'aboslute_path_to_restore_directory' -- such as 'c:\temp\'
-- Create the backup file name based on the restore directory, the database name and today's date
set @backupFileName = @restoreDirectory + @databaseName + '-' + replace(convert(varchar, getdate(), 110), '-', '.') + '.bak'
-- Get the data file and its path
select @databaseDataFile = rtrim([Name]),
@databaseDataFilename = rtrim([Filename])
from master.dbo.sysaltfiles as files
inner join
master.dbo.sysfilegroups as groups
on
files.groupID = groups.groupID
where DBID = (
select dbid
from master.dbo.sysdatabases
where [Name] = @databaseName
)
-- Get the log file and its path
select @databaseLogFile = rtrim([Name]),
@databaseLogFilename = rtrim([Filename])
from master.dbo.sysaltfiles as files
where DBID = (
select dbid
from master.dbo.sysdatabases
where [Name] = @databaseName
)
and
groupID = 0
print 'Killing active connections to the "' + @databaseName + '" database'
-- Create the sql to kill the active database connections
set @execSql = ''
select @execSql = @execSql + 'kill ' + convert(char(10), spid) + ' '
from master.dbo.sysprocesses
where db_name(dbid) = @databaseName
and
DBID <> 0
and
spid <> @@spid
exec (@execSql)
print 'Restoring "' + @databaseName + '" database from "' + @backupFileName + '" with '
print ' data file "' + @databaseDataFile + '" located at "' + @databaseDataFilename + '"'
print ' log file "' + @databaseLogFile + '" located at "' + @databaseLogFilename + '"'
set @execSql = '
restore database [' + @databaseName + ']
from disk = ''' + @backupFileName + '''
with
file = 1,
move ''' + @databaseDataFile + ''' to ' + '''' + @databaseDataFilename + ''',
move ''' + @databaseLogFile + ''' to ' + '''' + @databaseLogFilename + ''',
norewind,
nounload,
replace'
exec sp_executesql @execSql
exec('use ' + @databaseName)
go
-- If needed, restore the database user associated with the database
/*
exec sp_revokedbaccess 'myDBUser'
go
exec sp_grantdbaccess 'myDBUser', 'myDBUser'
go
exec sp_addrolemember 'db_owner', 'myDBUser'
go
use master
go
*/
Posted by
Boyan Kostadinov
at
15:37
15
Comments
| Share this post: |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Categories: SQL Server, T-SQL, Utilities
Wednesday, October 17, 2007
SQL Server Script to Backup a Database to File
I frequently have to backup a database from the production machine and restore it in my testing environment. You can do this with SQL Server Enterprise Manager (or other similar tools) but it can get to be a pain if you have to it over and over again. So here is a script to do the first part - backup a database from a sql server to a file. For the second part, please see my related post called SQL Server Script to Restore a Database from File. To use this script you need to:
- Set the database name in the @databaseName variable to your database
- Set the absolute path for the backup directory in the @backupDirectory variable to the directory where the backup will be created
- Run the script (with something like Query Analyzer)
Download the script from http://tech-cats.net/blog/downloads/sql/SQLServerBackupDatabaseToFile.txt
----------------------------------------------------------------- -- Backup database to file ----------------------------------------------------------------- declare @backupFileName varchar(100), @backupDirectory varchar(100), @databaseDataFilename varchar(100), @databaseLogFilename varchar(100), @databaseDataFile varchar(100), @databaseLogFile varchar(100), @databaseName varchar(100), @execSql varchar(1000) -- Set the name of the database to backup set @databaseName = 'myDatabase' -- Set the path fo the backup directory on the sql server pc set @backupDirectory = 'aboslute_path_to_backup_directory' -- such as 'c:\temp\' -- Create the backup file name based on the backup directory, the database name and today's date set @backupFileName = @backupDirectory + @databaseName + '-' + replace(convert(varchar, getdate(), 110), '-', '.') + '.bak' -- Get the data file and its path select @databaseDataFile = rtrim([Name]), @databaseDataFilename = rtrim([Filename]) from master.dbo.sysaltfiles as files inner join master.dbo.sysfilegroups as groups on files.groupID = groups.groupID where DBID = ( select dbid from master.dbo.sysdatabases where [Name] = @databaseName ) -- Get the log file and its path select @databaseLogFile = rtrim([Name]), @databaseLogFilename = rtrim([Filename]) from master.dbo.sysaltfiles as files where DBID = ( select dbid from master.dbo.sysdatabases where [Name] = @databaseName ) and groupID = 0 print 'Backing up "' + @databaseName + '" database to "' + @backupFileName + '" with ' print ' data file "' + @databaseDataFile + '" located at "' + @databaseDataFilename + '"' print ' log file "' + @databaseLogFile + '" located at "' + @databaseLogFilename + '"' set @execSql = ' backup database [' + @databaseName + '] to disk = ''' + @backupFileName + ''' with noformat, noinit, name = ''' + @databaseName + ' backup'', norewind, nounload, skip' exec(@execSql)
Posted by
Boyan Kostadinov
at
12:23
4
Comments
| Share this post: |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Categories: SQL Server, T-SQL, Utilities
Tuesday, October 16, 2007
Unzip with UTF Support in ColdFusion - Function Updates for v0.2
Due to some shortcommings, here is an update of the "unzipWithUTFSupport" function. The change log is below. You can get the update version at http://tech-cats.net/blog/downloads/coldFusion/unzipWithUTFSupportUDF.txt
- Support for absolute paths relative to the root of the web site
Example: destination = "/"
- Back slashes get converted to forward slashes
Example: destination = "/test\blah" = "/test/blah"
- Better support for relative paths:
- relative to the "destination" if one is specified
- relative to the name of the zip archive otherwise (which is used as the extract directory name)
- Support for parent paths (relative to the executing script)
Example: destination = "../test"
- Support for absolute paths
Example: destination = "d:\webroot\test"
- All possible ways to define a path also apply to the "destination" key in the locationsByFileType structure
Example: locationsByFileType.jpg.destination = "images\jpg"
- No need for file type sub structure if you only care for the path where the files will be extracted
Example: locationsByFileType.xml = "images\jpg"
Instead of: locationsByFileType.jpg.destination = "images\jpg"
- Corrected an omission in the build script that prevented all files from being extracted because of lower case or upper case file extensions
- Renamed "overwriteDestination" to "deleteDestination" and set it to "false" by default
Posted by
Boyan Kostadinov
at
19:33
0
Comments
| Share this post: |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Categories: Ant, ColdFusion, Updates, Utilities
DriverMax - Reinstall your Windows Drivers within Minutes
Why didn't anybody think of this before?! Reinstalling your hardware drivers can always be a pain when reinstalling Windows. This program aims to backup your installed drivers so when you have to reinstall Windows, you can easily restore your drivers from the backup. DriverMax for Windows Vista and Windows XP - easily reinstall all your Windows drivers within a few minutes
Posted by
Boyan Kostadinov
at
10:02
0
Comments
| Share this post: |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Monday, October 15, 2007
Unzip with UTF Support in ColdFusion Curtosy of Ant via cfant
Update: Function was updated to v0.2 (see Unzip with UTF Support in ColdFusion - Function Updates for v0.2)
A fellow by the name of Ricardo Parente contacted me today about unzipping a zip file that contains files with special characters (to be more technical, the file names were using UTF8 encoding). Some filenames contained accents and/or other characters that would cause issues. He was trying to extract the zip file programmatically using the zip component from Alagad but that was throwing an exception. After looking around for a bit, turns out there is allready an existing user defined function on cflib called unzipFile. However, it seems that suffered from the same problem as the Alagad component when trying to extract files with UTF8 encoding. So after some searching, I found that the UTF encoding issue is an issue with Java and has not be fixed for 6 years!! Bah! So anyway, it turns out Ant, does support that with no problem and forutnatelly ColdFusion MX 7 comes with the undocumented function "cfant". So here is the custom function to unzip those pesky zip files contained UTF encoded file names. Createvely, I've named it "unzipWithUTFSupport". You can call it as simple as:
<cfset unzipResults = unzipWithUTFSupport("myUTFEncodedZipFile.zip") />
or like so to specify the destination directory:
<cfset unzipResults = unzipWithUTFSupport( zipFile = "myUTFEncodedZipFile.zip", destination = "yourRelativeDestination" ) />This will return a structure with the following keys:
- antMessage = string with the message Ant returned
- argumentErrors = array of argument validation errors
- fileList = query of files unzipped
- success = boolean indicating the success or the failure of the unzip process
<cfset locationsByFileType = structnew() /> <cfset locationsByFileType.jpg = structnew() /> <cfset locationsByFileType.jpg.destination = "images" />Once you configure the "locationsByFileType" structure, you just pass it to the function like so:
<cfset results = unzipWithUTFSupport( zipFile = "myUTFEncodedZipFile.zip", extractLocationsByFileType = locationsByFileType ) />The important think to keep in mind is that, if you use this functionality, you will have to define the configurtion for each file type. This means that if you use the configuration above, only ".jpg" files will be extracted from the zip archive. This will return a structure with the following keys:
- antMessage = string with the message Ant returned
- argumentErrors = array of argument validation errors
- fileList = a structure of queries with the unzipped files under each file extension
- success = boolean indicating the success or the failure of the unzip process
- specialCharsMatchRegEx = string with the regular expression that will match the special characters in the file names (by default "[^A-Za-z0-9\._\-]")
- replaceSpecialChars = boolean indicating if special characters in the file names should be replaced (by default true)
<cfset locationsByFileType = structnew() /> <cfset locationsByFileType.jpg = structnew() /> <cfset locationsByFileType.jpg.destination = "images" /> <cfset locationsByFileType.jpg.replaceSpecialChars = false /> <cfset locationsByFileType.jpg.specialCharsMatchRegEx = "[^A-Za-z0-9\._\-]" />Finally, here is the function code
<!---
Function: unzipWithUTFSupport
Created on: 10.15.2007
Author: Boyan Kostadinov
Version: 0.1
Arguments: zipFile (string) required
The name of the zip file to extract
destination (string)
The relative destination directory to extract the zip to (by default ".")
overwriteDestination (boolean)
Should the destination directory to be overwritte (by default true)
extractLocationsByFileType (struct)
A structure containing the type of files to be extracted
and their destinations (by default empty structure)
Example:
<cfset locationsByFileType.jpg = structnew() />
Specify the relative destination where to extract this type of files
<cfset locationsByFileType.jpg.destination = "jpgFilesDir" />
Should special characters be replaced for this type of files
<cfset locationsByFileType.jpg.replaceSpecialChars = true />
The regular expression to match special characters against
<cfset locationsByFileType.jpg.specialCharsMatchRegEx = "[^A-Za-z0-9\._\-]" />
If "replaceSpecialChars" and "specialCharsMatchRegEx" do not exist, the default
values in the functions are used (true and "[^A-Za-z0-9\._\-]")
replaceSpecialChars (boolean)
Should special characters in the file names be replaced (by default true)
specialCharsMatchRegEx (string)
The regular expression that will match the special characters in the file names
that need to replaced (by default "[^A-Za-z0-9\._\-]")
Return Value: unzipResults (struct)
A structure containing the results of the unzip process with the keys:
success (boolean)
the sucess of the unzip
antMessage (string)
the message the unzip task returns
fileList (struct)
the list of files/directories unzipped
Description: I extract a zip file no matter of encoding with the help of Ant
--->
<cffunction name="unzipWithUTFSupport" hint="I extract a zip file no matter of encoding with the help of Ant" returntype="struct">
<cfargument name="zipFile" type="string" required="yes" />
<cfargument name="destination" type="string" required="no" default="." />
<cfargument name="overwriteDestination" type="boolean" required="no" default="true" />
<cfargument name="extractLocationsByFileType" type="struct" required="no" default="#structnew()#" />
<cfargument name="replaceSpecialChars" type="boolean" required="no" default="true" />
<cfargument name="specialCharsMatchRegEx" type="string" required="no" default="[^A-Za-z0-9\._\-]" />
<!--- Create local variables for the zip file name and the destination directory --->
<cfset var zipFileName = "" />
<cfset var unzipDestination = "" />
<cfset var uniqueUnzipDestinationDirectory = "" />
<cfset var unzipResults = structnew() />
<cfset var buildMessage = "" />
<cfset var currentDir = "" />
<cfset var fileRenamed = false />
<!--- Set the name of the temporary ant build file --->
<cfset var buildFile = expandpath("unzip.xml") />
<cfset unzipResults.success = false />
<cfset unzipResults.antMessage = "" />
<cfset unzipResults.fileList = 0 />
<cfset unzipResults.argumentErrors = arraynew(1) />
<!--- Set the name of the zip file to extract --->
<cfif arguments.zipFile neq "">
<cfset zipFileName = expandPath(arguments.zipFile) />
<cfif not fileExists(zipFileName)>
<cfset arrayappend(unzipResults.argumentErrors, "The zip file #arguments.zipFile# was not found") />
</cfif>
<cfelse>
<cfset arrayappend(unzipResults.argumentErrors, "The zip file was not specified") />
</cfif>
<!--- Set the extract destination --->
<cfif arguments.destination neq "">
<cfset unzipDestination = expandPath(arguments.destination) />
<cfelse>
<cfset arrayappend(unzipResults.argumentErrors, "Destination was empty") />
</cfif>
<!--- If there were not argument validation errors --->
<cfif arrayisempty(unzipResults.argumentErrors)>
<!--- Create a directory for the zip file based on the name of the zip archive --->
<cfset uniqueUnzipDestinationDirectory =
unzipDestination & "\" &
rereplacenocase(arguments.zipFile, "\.zip$", "") />
<cfdump var="#uniqueUnzipDestinationDirectory#" />
<!--- Create the xml string for the ant build file --->
<cfoutput>
<!--- If the "extractLocationsByFileType" structure is not empty, loop over it
to extract the different files types to the specified sub directory --->
<cfsavecontent variable="unzipXml">
<project>
<target name="unzip">
<cfif not structisempty(extractLocationsByFileType)>
<cfloop list="#structKeyList(extractLocationsByFileType)#" index="key">
<cfif isstruct(extractLocationsByFileType[key])>
<unzip src="#zipFileName#" dest="#uniqueUnzipDestinationDirectory#\#lcase(extractLocationsByFileType[key].destination)#">
<patternset>
<include name="**/*.#lcase(key)#"/>
</patternset>
</unzip>
<cfelse>
<unzip src="#zipFileName#" dest="#uniqueUnzipDestinationDirectory#\#lcase(extractLocationsByFileType[key])#">
<patternset>
<include name="**/*.#lcase(key)#"/>
</patternset>
</unzip>
</cfif>
</cfloop>
<cfelse>
<unzip src="#zipFileName#" dest="#uniqueUnzipDestinationDirectory#" />
</cfif>
</target>
</project>
</cfsavecontent>
</cfoutput>
<cftry>
<!--- If the destination directory already exists, delete it --->
<cfif directoryExists(uniqueUnzipDestinationDirectory) and arguments.overwriteDestination>
<cfdirectory action="delete" directory="#uniqueUnzipDestinationDirectory#" recurse="yes" />
</cfif>
<!--- Write the temporary ant build file on the file system --->
<cffile action="write" nameconflict="overwrite" file="#buildFile#" output="#unzipXml#" />
<!--- Execute the ant task with the created ant build file --->
<!--- "messages" holds the coldfusion variable to write the ant output to --->
<!--- "target" is the name of the "defaultTarget" (ant speak) to execute when runing the ant task --->
<cfant buildFile="#buildFile#"
defaultDirectory=""
anthome=""
messages="buildMessage"
target="unzip"
/>
<cfif refindnocase(".*unable to expand to file.*", buildMessage)>
<cfset unzipResults.success = false />
<cfelseif refindnocase(".*build successful.*", buildMessage)>
<cfset unzipResults.success = true />
</cfif>
<cfset unzipResults.antMessage = buildMessage />
<!--- Delete the temporary ant build file --->
<cffile action="delete" file="#buildFile#" />
<cfif unzipResults.success>
<cfif not structisempty(extractLocationsByFileType)>
<cfset unzipResults.fileList = structnew() />
<cfloop list="#structKeyList(extractLocationsByFileType)#" index="key">
<cfif isstruct(extractLocationsByFileType[key])>
<cfset currentDir =
uniqueUnzipDestinationDirectory & "\" &
extractLocationsByFileType[key].destination />
<cfif structkeyexists(extractLocationsByFileType[key], "replaceSpecialChars")>
<cfif isboolean(extractLocationsByFileType[key].replaceSpecialChars)>
<cfset replaceSpecialChars = extractLocationsByFileType[key].replaceSpecialChars />
</cfif>
</cfif>
<cfif replaceSpecialChars>
<cfif structkeyexists(extractLocationsByFileType[key], "specialCharsMatchRegEx")>
<cfset specialCharsMatchRegEx = extractLocationsByFileType[key].specialCharsMatchRegEx />
</cfif>
</cfif>
<cfelse>
<cfset currentDir = uniqueUnzipDestinationDirectory & "\" &
extractLocationsByFileType[key] />
</cfif>
<!--- Get a list of the files in the directory --->
<cfdirectory
action="list"
directory="#currentDir#" name="currentFileList" />
<cfset fileRenamed = false />
<cfif replaceSpecialChars>
<!--- Loop over all the files --->
<cfloop query="currentFileList">
<!--- If the filename has special characters --->
<cfif refind(specialCharsMatchRegEx, name)>
<!--- Create a new name for the file by replacing all special characters with "_" --->
<cfset newName = rereplace(name, specialCharsMatchRegEx, "_", "all") />
<!--- Rename the file to the new name --->
<cffile
action="rename"
source="#directory#\#name#"
destination="#directory#\#newName#" />
<cfset fileRenamed = true />
</cfif>
</cfloop>
</cfif>
<cfif fileRenamed>
<!--- Get a list of the files in the directory
(again since some files might have been renamed) --->
<cfdirectory
action="list"
directory="#currentDir#" name="currentFileList" />
</cfif>
<cfset unzipResults.fileList[key] = currentFileList />
</cfloop>
<cfelse>
<!--- Get a list of the files in the directory --->
<cfdirectory
action="list"
directory="#uniqueUnzipDestinationDirectory#" name="currentFileList" />
<cfset fileRenamed = false />
<cfif arguments.replaceSpecialChars and specialCharsMatchRegEx neq "">
<!--- Loop over all the files --->
<cfloop query="currentFileList">
<!--- If the filename has special characters --->
<cfif refind(specialCharsMatchRegEx, name)>
<!--- Create a new name for the file by replacing all special characters with "_" --->
<cfset newName = rereplace(name, specialCharsMatchRegEx, "_", "all") />
<!--- Rename the file to the new name --->
<cffile
action="rename"
source="#directory#\#name#"
destination="#directory#\#newName#" />
<cfset fileRenamed = true />
</cfif>
</cfloop>
</cfif>
<cfif fileRenamed>
<!--- Get a list of the files in the directory
(again since some files might have been renamed) --->
<cfdirectory
action="list"
directory="#uniqueUnzipDestinationDirectory#" name="currentFileList" />
</cfif>
<cfset unzipResults.fileList = currentFileList />
</cfif>
</cfif>
<cfcatch type="any">
<cfdump var="#cfcatch#" />
</cfcatch>
</cftry>
</cfif>
<cfreturn unzipResults />
</cffunction>
Posted by
Boyan Kostadinov
at
19:25
0
Comments
| Share this post: |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Categories: Ant, ColdFusion, Utilities
Friday, October 12, 2007
Get a User's Primary Group Membership from Active Directory with ColdFusion
Recently, I've had to do much work with Active Directory/LDAP. I needed a way to grab the user's primary group so I can set some permissions in my application based on the primary group the user is a member of. This turned out to be a bit tricky since the primary group for each user is not part of the list of groups the user is a member of. Instead, the primary group token (just an ID) is stored in each user's record. Seems pretty simple now that I got it working but there was a big lack of documentation on how to do this in ColdFusion. So here is the psudo code:
- We need to query Active Directory and get the value of the "primaryGroupID" for the selected user
- We also need a full list of groups in Active Directory (this is acheived with using the filter "(&(objectcategory=group))")
- Next, we need to get the group name from the full list of groups based on the primary group token we got from the user's record
- Bingo!
<!--- Get the primary group id for an example user ---> <cfldap action="query" name="userLdapQuery" start="dc=ica,dc=com" server="ldapServer" username="ldapUser" password="secretPassword" scope="subtree" filter="sAMAccountName=bkostadinov" attributes="primaryGroupID" timeout="0" maxrows="1" /> <!--- Query the ldap server for the full list of groups ---> <cfldap action="query" name="groupsQuery" start="dc=ica,dc=com" server="ldapServer" username="ldapUser" password="secretPassword" scope="subtree" filter="(&(objectcategory=group))" attributes="primaryGroupToken,name" timeout="0" /> <!--- Beacause the list of groups the user belongs to, does not contain the user's primary group, query the ldap groups to get only the group name for witch the value of the primaryGroupTokenAttribute matches the value of the primaryGroupIDAttribute ---> <cfquery name="primaryGroupQuery" dbtype="query"> select lower(name) as name from groupsQuery where primaryGroupToken = '#userLdapQuery.primaryGroupID#' </cfquery> <!--- Get the primary group name from the query resutls ---> <cfset primaryGroup = primaryGroupQuery["name"][1] />
Thursday, October 11, 2007
Must Have Tools for Windows Power Users
This is a list of must have tools with inspiration from blog post at http://www.nodans.com/index.cfm/2007/10/10/Dana-Kowalski-sez-Crack-Open-your-Toolbox-and-Share
Launchy: http://www.launchy.net/ - An open source keystroke launcher for Windows
XYPlorer: http://www.xyplorer.com - A windows file manager and explorer replacement
Hamachi: http://hamachi.cc/download/list.php - Software based VPN
FolderShare: http://www.foldershare.com - Sync files/directories between multiple computers
RoboForm: http://www.roboform.com - An automated form filer and password manager
Altiris Software Virtualization: http://www.svsdownloads.com - A virtual engine for applications
Paint.NET: http://www.svsdownloads.com - Free image and photo editing software
Quest Comparison Suite for SQL Server: http://www.quest.com/Comparison-Suite-for-SQL-Server - Free Microsoft SQL server comparison suite
Tuesday, October 09, 2007
Neat Prototype Trick - Activate First Form Element Without a Certain Class Name
Let's say you have form with a bunch of fields that you have disabled with the "read only" attribute so the user can't change the data. Also, you have applied a css class called "readOnlyInput" so you can style the input field as read only field (different color or whatever else you like). I had such form this evening but I wanted the focus to automatically go to the first non read only element when the page is loaded. Usually, you can pass focus on a form element by doing this:
// 'myFormField' is the id of form field you want to focus on
$('myFormField').focus();
However, if the input field already contains data, you might want to focus the field and highlight it in the same time. In that case you will do:
// 'myFormField' is the id of form field you want to focus on
$('myFormField').activate();
That is all fine and great but what when I have a bunch of input elements and some of them might be marked "read only". To make things more complicated (as I love to do), I would hate to hard code the id of the first element I want to focus/activate. So here is the solution:
// For each input element on the form
$A($('myForm').getInputs()).each(function(formElement) {
// If the form element does not have the class "readOnlyInput"
if (!$(formElement).hasClassName('readOnlyInput')) {
// Activate that element
$(formElement).activate();
// Break out of the loop (prototype specific syntax here)
throw $break;
}
});
Just so Doug's kids would understand this, here it is in psudo code:
- Get a list of form input elements by using Prototype's built in "getInputs" function $('myForm').getInputs()
- Convert the list of form inputs to a Prototype array $A($('myForm').getInputs())
- Now for each of the elements in the array, run a function pass in the current element $A($('myForm').getInputs()).each(function(formElement)
- If the current form element has a css class not matching "readOnlyInput" if (!$(formElement).hasClassName('readOnlyInput'))
- Activate that form element $(formElement).activate();
- We found the first element so break out of the loop throw $break;
Monday, October 08, 2007
ColdFusion CFC Scope Exploration
Doug Boude's post at http://www.dougboude.com/blog/1/2007/10/Appropriate-Usage-of-the-THIS-Scope.cfm, prompted me to create this simple test that should show the difference between using the "this" scope, the "variables" scope and the "var" scope. Here is what you need to get things setup. Declare a test component as follows:
<cfcomponent displayname="thisScopeToUseOrNotToUse"> <cffunction name="testMethod"> <!--- Create a variable in the local scope of the function ---> <cfset var iAmAccessableOnlyWithinThisMethod = true /> <!--- Create a variable in the "this" scope ---> <cfset this.iAmAccessableFromOutside = true /> <!--- Create variable in the private component scope ---> <cfset variables.iAmAccessableOnlyWithinThisCFC = true /> </cffunction> <cffunction name="getIAmAccessableOnlyWithinThisCFCButCanBeViewedFromTheOutsideWithAPublicMethod"> <cfreturn variables.iAmAccessableOnlyWithinThisCFC /> </cffunction> </cfcomponent>Then declare a test file as follows:
<cfset testCFC = createObject("component", "thisScopeToUseOrNotToUse") />
<cfset testCFC.testMethod() />
=======================================
<p />
Try to read a variable declare in the "this" scope of the component
<p />
<strong>iAmAccessableFromOutside:</strong>
<cfdump var="#testCFC.iAmAccessableFromOutside#" />
<p />
=======================================
<p />
Try to read a variable declared in the private component scope (the "variables" scope)
<p />
<strong>iAmAccessableOnlyWithinThisCFC:</strong>
<cftry>
<cfdump var="#testCFC.iAmAccessableOnlyWithinThisCFC#" />
<cfcatch type="any">
<cfdump var="#cfcatch.message#" />
</cfcatch>
</cftry>
<p />
=======================================
<p />
Using a public method to read a variable in the private component scope (the "variables" scope):
<p />
<strong>getIAmAccessableOnlyWithinThisCFCButCanBeViewedFromTheOutsideWithAPublicMethod:</strong>
<cfoutput>#testCFC.getIAmAccessableOnlyWithinThisCFCButCanBeViewedFromTheOutsideWithAPublicMethod()#</cfoutput>
<p />
=======================================
<p />
<strong>Trying to read a variable declared only in the method scope:
<p />
iAmAccessableOnlyWithinThisMethod:</strong>
<cftry>
<cfdump var="#testCFC.iAmAccessableOnlyWithinThisMethod#" />
<cfcatch type="any">
<cfdump var="#cfcatch.message#" />
</cfcatch>
</cftry>
Here are the results:
Now, for the explanation:
- First we create a instance of the compontent with "createObject"
- Call the "testMethod" of the component so we can set the variables
- Then we try to access the "iAmAccessableFromOutside" variable and get "true" since that was the value set to the variable in the "testMethod" function
- Next, we try to read a variable declared in the private component scope "iAmAccessableOnlyWithinThisCFC". The code block is wrapped with "cfcatch" so we get a nice error message when ColdFusion cannot access the privately declare variable
- However, we can use the method "getIAmAccessableOnlyWithinThisCFCButCanBeViewedFromTheOutsideWithAPublicMethod" which just returns the private scope variable "iAmAccessableOnlyWithinThisCFC"
- Lastly, we try to access the variable "iAmAccessableOnlyWithinThisMethod" which was declared in the private "var" scope of the "testMethod" function. The code block is wrapped with "cfcatch" so we get a nice error message when ColdFusion cannot access the privately declare variable
Friday, October 05, 2007
Web Page Syntax Highlighting for ColdFusion - Brush for SyntaxHighlighter
I have been working on a implementing a solution to highlight ColdFusion code snippets when they are being posted on your web site/blog. Highlighting the code according to the appropriate language can make it much easier to read and comprehend (and make it pretty of course). To do this, I have created a ColdFusion syntax "brush" for the JavaScript highlighter SyntaxHighlighter (formally dp.SyntaxHighlighter). In this context, a "brush" is a set of language specific settings for highlighting/prettifying code. SyntaxHighlighter is a pretty cool piece of software and I had some fun and faced some challenges while trying to create ColdFusion specific highlighting brush. Here is a demo of the highlighter at work when given ColdFusion code snippet:
<cfcomponent displayname="applicationController" extends="ModelGlue.unity.controller.Controller" output="false">
<cfscript>
// Set component variables
variables.appConfig = 0;
variables.modelGlueConfig = 0;
variables.rolePermissions = structnew();
variables.userIDWithAdminRights = "";
</cfscript>
<!---
Function: name="changeUserSiteRole"
Created on: 09.25.2007
Updated on: 09.25.2007
Author: Boyan Kostadinov
Arguments: event(ModelGlue.Core.Event)
Return Value: none
Description:
--->
<cffunction name="changeUserSiteRole" access="public" returntype="void" output="false">
<cfargument name="event" type="ModelGlue.Core.Event">
<cfset var userID = arguments.event.getValue("userID", 0) />
<cfset var siteID = arguments.event.getValue("siteID", 0) />
<cfset var roleID = arguments.event.getValue("roleID", 0) />
<cfset var showAllUsers = arguments.event.getValue("showAllUsers", false) />
<cfif userID neq 0 and siteID neq 0 and roleID neq 0>
<!--- Call the changeUserSiteRole method in the UsersGateway to change the user's
role in the specified siteID --->
<cfset variables.usersGateway.changeUserSiteRole(userID, siteID, roleID) />
</cfif>
<cfif showAllUsers>
<cfset arguments.event.addResult("allUsers") />
<cfelse>
<cfset arguments.event.addResult("singleUser") />
</cfif>
</cffunction>
<cffunction name="onQueueComplete" access="public" returntype="void" output="false">
<cfargument name="event" type="any">
<cfset arguments.event.setValue("defaultEvent", getModelGlue().getBean("modelGlueConfiguration").getdefaultEvent()) />
<cfset arguments.event.setValue("appConfig", variables.appConfig) />
<cfset arguments.event.setValue("ApplicationVersion", variables.appConfig.GetConfigSetting("ApplicationVersion")) />
<cfset arguments.event.setValue("ApplicationLastRevisionDate", variables.appConfig.GetConfigSetting("ApplicationLastRevisionDate")) />
<cfset arguments.event.setValue("urlPrefix", variables.defaultTemplate & "?" & arguments.event.getValue("eventValue") & "=") />
<cfset arguments.event.setValue("CurrentPageUrl", getfilefrompath(cgi.script_name) & "?" & cgi.query_string) />
</cffunction>
<cffunction name="onRequestEnd" access="public" returntype="void" output="false">
<cfargument name="event" type="any">
</cffunction>
</cfcomponent>
To install the SyntaxHighlighter on your page:
- Get it http://code.google.com/p/syntaxhighlighter/
- Extract it somewhere accessable from the web
- Add the following code
<!-- Include the SyntaxHighlighter stylesheet --> <style type="text/css" media="screen">@import url("pathToSyntaxHighlighterStyle/syntaxHighlighter.css");</style> <!-- Include the core SyntaxHighlighter library --> <script language="javascript" src="pathToSyntaxHighlighter/scripts/shCore.js"></script> <!-- Include the ColdFusion brush --> <script language="javascript" src="pathToSyntaxHighlighter/scripts/shBrushColdFusion.js"></script> <script language="javascript"> window.onload = function () { // Set the path to the flash component to enable 'copy to clipboard' in firefox dp.SyntaxHighlighter.ClipboardSwf = 'pathToSyntaxHighlighter/scripts/clipboard.swf'; // Enable blogger mode (if using Blogger) dp.SyntaxHighlighter.BloggerMode(); // Highlight page elements with the name "code" // For configuration options see http://code.google.com/p/syntaxhighlighter/wiki/HighlightAll dp.SyntaxHighlighter.HighlightAll('code', false, true, false, 1, false); } </script> - Modify the css for your preferences (Firebug is really handy here to figure out what classes you want to modify). Here are my changes:
<style type="text/css"> .dp-highlighter ol li, .dp-highlighter .columns div { padding: 0px 3px 0px 0px !important; font-size: 12px !important; font-family: 'Lucida Console', 'Bitstream Vera Sans Mono', 'Courier New', Monaco, Courier, monospace; } .dp-highlighter .tools { padding-left: 0px; } .dp-highlighter .tools a { color: #000; text-decoration: underline; } .dp-highlighter .tools a:hover { margin-right: 10px; } </style> - Add some more brushes. For supported languages are C++, C#, CSS, Delphi, Java, JavaScript, PHP, Pythod, Ruby, SQL, VB, XML, HTML, XLST and now ColdFusion :-). More information on the languages at http://code.google.com/p/syntaxhighlighter/wiki/Languages.Here are the brushes I am using:
<script language="javascript" src="scripts/shBrushCSharp.js"></script> <script language="javascript" src="scripts/shBrushCss.js"></script> <script language="javascript" src="scripts/shBrushJScript.js"></script> <script language="javascript" src="scripts/shBrushSql.js"></script> <script language="javascript" src="scripts/shBrushVb.js"></script> <script language="javascript" src="scripts/shBrushXml.js"></script>
- Post your code enclosed in "<pre>" tags as follows:
<!-- For xml/html/xslt code --> <pre class="xml" name="code"> <!-- For css code --> <pre class="css" name="code"> <!-- For coldfusion code --> <pre class="cf" name="code"> <!-- For sql code --> <pre class="sql" name="code">
- Highlights ColdFusion functions, tags, attributes, strings, numbers, comments, cfscript comments
- Highlights a very limited set of Model-Glue specific keywords (I got adventures)
- Uses the Dreamweaver color shema to apply the syntax highlighting
- To just use it (without modifications), just include the compressed version from the svn location at http://opensourceprojects.googlecode.com/svn/dpSyntaxHighlighterColdFusionBrush/trunk/compressed/shBrushColdFusion.js
- To use it but modify the css styles, get the uncompressed version from http://opensourceprojects.googlecode.com/svn/dpSyntaxHighlighterColdFusionBrush/trunk/uncompressed/shBrushColdFusion.js and modify the css definitions in "this.Style"
- Include it as a brush in your page:
<script language="javascript" src="pathTo_shBrushColdFusion.js"></script>
dp.sh.Brushes.ColdFusion = function()
{
this.CssClass = 'dp-coldfusion';
this.Style = '.dp-coldfusion { font: 13px "Courier New", Courier, monospace; }' +
'.dp-coldfusion .tag, .dp-coldfusion .tag-name { color: #990033; }' +
'.dp-coldfusion .attribute { color: #990033; }' +
'.dp-coldfusion .attribute-value { color: #0000FF; }' +
'.dp-coldfusion .cfcomments { background-color: #FFFF99; color: #000000; }' +
'.dp-coldfusion .cfscriptcomments { color: #999999; }' +
'.dp-coldfusion .keywords { color: #0000FF; }' +
'.dp-coldfusion .mgkeywords { color: #CC9900; }' +
'.dp-coldfusion .numbers { color: #ff0000; }' +
'.dp-coldfusion .strings { color: green; }';
this.mgKeywords = 'setvalue getvalue addresult viewcollection viewstate';
this.keywords = 'var eq neq gt gte lt lte not and or true false ' +
'abs acos addsoaprequestheader addsoapresponseheader ' +
'arrayappend arrayavg arrayclear arraydeleteat arrayinsertat ' +
'arrayisempty arraylen arraymax arraymin arraynew ' +
'arrayprepend arrayresize arrayset arraysort arraysum ' +
'arrayswap arraytolist asc asin atn binarydecode binaryencode ' +
'bitand bitmaskclear bitmaskread bitmaskset bitnot bitor bitshln ' +
'bitshrn bitxor ceiling charsetdecode charsetencode chr cjustify ' +
'compare comparenocase cos createdate createdatetime createobject ' +
'createobject createobject createobject createobject createodbcdate ' +
'createodbcdatetime createodbctime createtime createtimespan ' +
'createuuid dateadd datecompare dateconvert datediff dateformat ' +
'datepart day dayofweek dayofweekasstring dayofyear daysinmonth ' +
'daysinyear de decimalformat decrementvalue decrypt decryptbinary ' +
'deleteclientvariable directoryexists dollarformat duplicate encrypt ' +
'encryptbinary evaluate exp expandpath fileexists find findnocase ' +
'findoneof firstdayofmonth fix formatbasen generatesecretkey ' +
'getauthuser getbasetagdata getbasetaglist getbasetemplatepath ' +
'getclientvariableslist getcontextroot getcurrenttemplatepath ' +
'getdirectoryfrompath getencoding getexception getfilefrompath ' +
'getfunctionlist getgatewayhelper gethttprequestdata gethttptimestring ' +
'getk2serverdoccount getk2serverdoccountlimit getlocale ' +
'getlocaledisplayname getlocalhostip getmetadata getmetricdata ' +
'getpagecontext getprofilesections getprofilestring getsoaprequest ' +
'getsoaprequestheader getsoapresponse getsoapresponseheader ' +
'gettempdirectory gettempfile gettemplatepath gettickcount ' +
'gettimezoneinfo gettoken hash hour htmlcodeformat htmleditformat ' +
'iif incrementvalue inputbasen insert int isarray isbinary isboolean ' +
'iscustomfunction isdate isdebugmode isdefined isk2serverabroker ' +
'isk2serverdoccountexceeded isk2serveronline isleapyear islocalhost ' +
'isnumeric isnumericdate isobject isquery issimplevalue issoaprequest ' +
'isstruct isuserinrole isvalid isvalid isvalid iswddx isxml ' +
'isxmlattribute isxmldoc isxmlelem isxmlnode isxmlroot javacast ' +
'jsstringformat lcase left len listappend listchangedelims listcontains ' +
'listcontainsnocase listdeleteat listfind listfindnocase listfirst ' +
'listgetat listinsertat listlast listlen listprepend listqualify ' +
'listrest listsetat listsort listtoarray listvaluecount ' +
'listvaluecountnocase ljustify log log10 lscurrencyformat lsdateformat ' +
'lseurocurrencyformat lsiscurrency lsisdate lsisnumeric lsnumberformat ' +
'lsparsecurrency lsparsedatetime lsparseeurocurrency lsparsenumber ' +
'lstimeformat ltrim max mid min minute month monthasstring now ' +
'numberformat paragraphformat parameterexists parsedatetime pi ' +
'preservesinglequotes quarter queryaddcolumn queryaddrow querynew ' +
'querysetcell quotedvaluelist rand randomize randrange refind ' +
'refindnocase releasecomobject removechars repeatstring replace ' +
'replacelist replacenocase rereplace rereplacenocase reverse right ' +
'rjustify round rtrim second sendgatewaymessage setencoding ' +
'setlocale setprofilestring setvariable sgn sin spanexcluding ' +
'spanincluding sqr stripcr structappend structclear structcopy ' +
'structcount structdelete structfind structfindkey structfindvalue ' +
'structget structinsert structisempty structkeyarray structkeyexists ' +
'structkeylist structnew structsort structupdate tan timeformat ' +
'tobase64 tobinary toscript tostring trim ucase urldecode urlencodedformat ' +
'urlsessionformat val valuelist week wrap writeoutput xmlchildpos ' +
'xmlelemnew xmlformat xmlgetnodetype xmlnew xmlparse xmlsearch xmltransform ' +
'xmlvalidate year yesnoformat';
// Array to hold the possible string matches
this.stringMatches = new Array();
this.attributeMatches = new Array();
}
dp.sh.Brushes.ColdFusion.prototype = new dp.sh.Highlighter();
dp.sh.Brushes.ColdFusion.Aliases = ['coldfusion', 'cf'];
dp.sh.Brushes.ColdFusion.prototype.ProcessRegexList = function()
{
function push(array, value)
{
array[array.length] = value;
}
function find(array, element)
{
for(var i = 0; i < array.length; i++){
if(array[i] == element){
return i;
}
}
return -1;
}
var match = null;
var regex = null;
// Match numbers
// (\\d+)
this.GetMatches(new RegExp('\\b(\\d+)', 'gm'), 'numbers');
// Match mg keywords
this.GetMatches(new RegExp(this.GetKeywords(this.mgKeywords), 'igm'), 'mgkeywords');
// Match single line comments via the built in single line regex (for cfscript)
this.GetMatches(dp.sh.RegexLib.SingleLineCComments, 'cfscriptcomments');
// Match multi line comments via the built in multi line regex (for cfscript)
this.GetMatches(dp.sh.RegexLib.MultiLineCComments, 'cfscriptcomments');
// Match tag based comments (including multiline comments)
// (\<|<)!---[\\s\\S]*?---(\>|>)
this.GetMatches(new RegExp('(\<|<)!---[\\s\\S]*?---(\>|>)', 'gm'), 'cfcomments');
// Match attributes and their values excluding cfset tags
// (cfset\\s*)?([:\\w-\.]+)\\s*=\\s*(".*?"|\'.*?\')*
regex = new RegExp('(cfset\\s*)?([:\\w-\.]+)\\s*=\\s*(".*?"|\'.*?\')*', 'gm');
while((match = regex.exec(this.code)) != null)
{
// If there is match in element 1 (the tag is cfset), continute to the next match
if (match[1] != undefined && match[1] != '')
{
continue;
}
// Add the atribute to the matches only if it has a matching value (dbtype="query")
// and the match is not an empty string
if (match[3] != undefined && match[3] != '' && match[3] != '""' && match[3] != "''")
{
push(this.matches, new dp.sh.Match(match[2], match.index, 'attribute'));
push(this.matches, new dp.sh.Match(match[3], match.index + match[0].indexOf(match[3]), 'attribute-value'));
// Add the attribute value to the array of string matches
push(this.stringMatches, match[3]);
// Add the attribute to the array of attribute matches
push(this.attributeMatches, match[2]);
}
}
// Match opening and closing tag brackets
// (\<|<)/*\?*(?!\!)|/*\?*(\>|>)
this.GetMatches(new RegExp('(\<|<)/*\\?*(?!\\!)|/*\\?*(\>|>)', 'gm'), 'tag');
// Match tag names
// (\<|<)/*\?*\s*(\w+)
regex = new RegExp('(?:\<|<)/*\\?*\\s*([:\\w-\.]+)', 'gm');
while((match = regex.exec(this.code)) != null)
{
push(this.matches, new dp.sh.Match(match[1], match.index + match[0].indexOf(match[1]), 'tag-name'));
}
// Match keywords
regex = new RegExp(this.GetKeywords(this.keywords), 'igm');
while((match = regex.exec(this.code)) != null)
{
// if a match exists (there is a value for the attribute)
if (find(this.attributeMatches, match[0]) == -1)
{
push(this.matches, new dp.sh.Match(match[0], match.index, 'keywords'));
}
}
// Match cfset tags and quoated attributes
regex = new RegExp('cfset\\s*.*(".*?"|\'.*?\')', 'gm');
while((match = regex.exec(this.code)) != null)
{
// if a match exists (there is a value for the attribute)
if(match[1] != undefined && match[1] != '')
{
push(this.matches, new dp.sh.Match(match[1], match.index + match[0].indexOf(match[1]), 'strings'));
// Add the attribute to the array of string matches
push(this.stringMatches, match[1]);
}
}
// Match string enclosed in double quoats
while((match = dp.sh.RegexLib.DoubleQuotedString.exec(this.code)) != null)
{
//if (this.stringMatches.indexOf(match[0]) == -1)
if (find(this.stringMatches, match[0]) == -1)
push(this.matches, new dp.sh.Match(match[0], match.index, 'strings'));
}
// Match string enclosed in single quoats
while((match = dp.sh.RegexLib.SingleQuotedString.exec(this.code)) != null)
{
//if (this.stringMatches.indexOf(match[0]) == -1)
if (find(this.stringMatches, match[0]) == -1)
push(this.matches, new dp.sh.Match(match[0], match.index, 'strings'));
}
}
Questions/comments? You can leave a comment here or use my contact form to send me your thoughts.
Posted by
Boyan Kostadinov
at
14:47
11
Comments
| Share this post: |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Categories: ColdFusion, tools, Utilities
Full List of ColdFusion Functions (according to DW)
Yesterday I needed a full list of ColdFusion functions for my syntax highlighting. What easier way to get that list than using your IDE?! I found the functions under the dreamweaver directory, in the file "configuration\CodeHints\CodeHints.hml". After some regex matching with the following pattern:
<function name="code" html? pattern="(\w+).*>and replacing with the following pattern:
$1Here is the list of ColdFusion functions that I got:
Abs ACos AddSOAPRequestHeader AddSOAPResponseHeader ArrayAppend ArrayAvg ArrayClear ArrayDeleteAt ArrayInsertAt ArrayIsEmpty ArrayLen ArrayMax ArrayMin ArrayNew ArrayPrepend ArrayResize ArraySet ArraySort ArraySum ArraySwap ArrayToList Asc ASin Atn BinaryDecode BinaryEncode BitAnd BitMaskClear BitMaskRead BitMaskSet BitNot BitOr BitSHLN BitSHRN BitXor Ceiling CharsetDecode CharsetEncode Chr Cjustify Compare CompareNoCase Cos CreateDate CreateDateTime CreateObject CreateObject CreateObject CreateObject CreateObject CreateODBCDate CreateODBCDateTime CreateODBCTime CreateTime CreateTimeSpan CreateUUID DateAdd DateCompare DateConvert DateDiff DateFormat DatePart Day DayOfWeek DayOfWeekAsString DayOfYear DaysInMonth DaysInYear DE DecimalFormat DecrementValue Decrypt DecryptBinary DeleteClientVariable DirectoryExists DollarFormat Duplicate Encrypt EncryptBinary Evaluate Exp ExpandPath FileExists Find FindNoCase FindOneOf FirstDayOfMonth Fix FormatBaseN GenerateSecretKey GetAuthUser GetBaseTagData GetBaseTagList GetBaseTemplatePath GetClientVariablesList GetContextRoot GetCurrentTemplatePath GetDirectoryFromPath GetEncoding GetException GetFileFromPath GetFunctionList GetGatewayHelper GetHTTPRequestData GetHTTPTimeString GetK2ServerDocCount GetK2ServerDocCountLimit GetLocale GetLocaleDisplayName GetLocalHostIP GetMetaData GetMetricData GetPageContext GetProfileSections GetProfileString GetSOAPRequest GetSOAPRequestHeader GetSOAPResponse GetSOAPResponseHeader GetTempDirectory GetTempFile GetTemplatePath GetTickCount GetTimeZoneInfo GetToken Hash Hour HTMLCodeFormat HTMLEditFormat IIf IncrementValue InputBaseN Insert Int IsArray IsBinary IsBoolean IsCustomFunction IsDate IsDebugMode IsDefined IsK2ServerABroker IsK2ServerDocCountExceeded IsK2ServerOnline IsLeapYear IsLocalHost IsNumeric IsNumericDate IsObject IsQuery IsSimpleValue IsSOAPRequest IsStruct IsUserInRole IsValid IsValid IsValid IsWDDX IsXML IsXMLAttribute IsXMLDoc IsXMLElem IsXMLNode IsXMLRoot JavaCast JSStringFormat LCase Left Len ListAppend ListChangeDelims ListContains ListContainsNoCase ListDeleteAt ListFind ListFindNoCase ListFirst ListGetAt ListInsertAt ListLast ListLen ListPrepend ListQualify ListRest ListSetAt ListSort ListToArray ListValueCount ListValueCountNoCase LJustify Log Log10 LSCurrencyFormat LSDateFormat LSEuroCurrencyFormat LSIsCurrency LSIsDate LSIsNumeric LSNumberFormat LSParseCurrency LSParseDateTime LSParseEuroCurrency LSParseNumber LSTimeFormat LTrim Max Mid Min Minute Month MonthAsString Now NumberFormat ParagraphFormat ParameterExists ParseDateTime Pi PreserveSingleQuotes Quarter QueryAddColumn QueryAddRow QueryNew QuerySetCell QuotedValueList Rand Randomize RandRange REFind REFindNoCase ReleaseCOMObject RemoveChars RepeatString Replace ReplaceList ReplaceNoCase REReplace REReplaceNoCase Reverse Right RJustify Round RTrim Second SendGatewayMessage SetEncoding SetLocale SetProfileString SetVariable Sgn Sin SpanExcluding SpanIncluding Sqr StripCR StructAppend StructClear StructCopy StructCount StructDelete StructFind StructFindKey StructFindValue StructGet StructInsert StructIsEmpty StructKeyArray StructKeyExists StructKeyList StructNew StructSort StructUpdate Tan TimeFormat ToBase64 ToBinary ToScript ToString Trim UCase URLDecode URLEncodedFormat URLSessionFormat Val ValueList Week Wrap WriteOutput XMLChildPos XMLElemNew XMLFormat XMLGetNodeType XMLNew XMLParse XMLSearch XMLTransform XMLValidate Year YesNoFormat
Wednesday, October 03, 2007
Readable ModelGlue Debugging Output while using CSS Layout
If you have your application layout done with CSS, most likely ModelGlue debugging output looks something like the picture below.
Overlaying the debug output with your application styles can make it a bit unreadable. So here is a tip. Get and install the Web Developer extension if you don't have it already. Once installed (and you restarted Firefox), go to the "CSS" menu and under "Disable Styles", click on "All Styles" (or use the shortcut key "Ctrl+Shift+S"). Here is a screen shot of doing so:
If you use Internet Explorer instead of Firefox, you can use the same thing with the Internet Explored Developer Toolbar by going to the "Disable" menu and click on "All CSS". Here is a screen shot of doing so:
Now your ModelGlue debugging output should look much cleaner and readable:

Free Ruby on Rails E-Book
Sitepoint.com is offering a free Ruby on Rails book called "Build Your Own Ruby on Rails Web Applications" by Patrick Lenz.
You can download the book in PDF format from the address
http://media.sitepoint.com/books/ror.pdf
Tuesday, October 02, 2007
Prototype.js Object Initialization and Bind While Enumerating Arrays
If the title sounds confusing, that is because it is. I couldn't figure out a better way to describe the issue I was running into. Let see if I can better demonstrate. I have a "initialize" function defined in my JavaScript object as such:
initialize: function() {
// siteID contains a list of ids such as "1,2,3,4"
// Convert the id list in siteIDs to a prototype array $A(siteIDs) and
// for each element in the array, run a function passing it the single siteID
$A(siteIDs).each(function(siteID) {
// If an element exists on the page with the id of setCurrentSiteElementPrefix + current siteID
if ($(this.setCurrentSiteElementPrefix + siteID)) {
// Add an observer to the 'click' event of that element and bind it
// to the 'getContent' function
$(this.setCurrentSiteElementPrefix + siteID).observe('click', this.getContent.bind(this));
}
});
}
where "siteIDs" is a comma delimited list of ids ("1,2,3,4") and "setCurrentSiteElementPrefix" is a part of the name of link element with a dynamically generated id (such as setCurrentSiteElementPrefix_1, setCurrentSiteElementPrefix_2). Here is the above loop in pseudo code (just for your kids Doug):
Convert the list of siteIDs to a prototype array and for each found array element, run a function passing the individual site id. $A(siteIDs) converts the list of site ids to an array, while .each() executes the inline function for each array element.
// $A(siteIDs).each(function(siteID)
If an element exists on the page with the id starting with setCurrentSiteElementPrefix (definition not shown here) + current siteID (passed by the inline function above)
// if ($(this.setCurrentSiteElementPrefix + siteID))
Add an observer to the
"click" event of that element and bind it to the "getContent" function. The "getContent" function has to bound to the "this" scope since the "getContent" function will not otherwise know what "this" means when trying to refer to elements defined in the object.
// $(this.setCurrentSiteElementPrefix + siteID).observe('click', this.getContent.bind(this));
Never mind why I am doing this, I will follow up on that with another post. So I was trying to tie an event observer to the 'click' event of each link element by looping through the list of dynamic ids ($A(siteIDs).each(function(siteID)). However, that was giving me some issues with the message "this.getContent is not defined". Why the heck not, the code is inside the "initialize" method of my object?! It turns out while looping over an array as above the "this" scope is not preserved. So the function inside the loop has no idea what "this" means. The simple fix is to surround the function with parenthesis and append ".bind(this)":
initialize: function() {
// Note the extra parenthesis before 'function(siteID)'
$A(siteIDs).each((function(siteID) {
if ($(this.setCurrentSiteElementPrefix + siteID)) {
$(this.setCurrentSiteElementPrefix + siteID).observe('click', this.getContent.bind(this));
}
}).bind(this));
// Note the ').bind(this)' before the semicolon
}
If you like to learn more on bind, check out Understanding bind and bindAsEventListener in Javascript and Understanding bind and bindAsEventListener in Javascript - Part II
Modifying Canvas ColdFusion Wiki
Canvas is an excellent wiki written by Ray Camden. It has a vast number of features for creating/maintaining documentation of any sort. I have been playing with it for a bit but I still haven't taken advantage of all its features. However, it lacks some basic features I thought it needed. I have been working on a side project and as a side effect I have added a few essentials (in my opinion). In subsequent posts, I will attempt to explain how to modify Canvas and add the following features:
- Database user authentication
- Persist user sessions between visits - "Remember Me" functionality
- LDAP user authentication
- Integration with Google Analytics
- Contact form
- Better exception handling / notifications
Loop Over ColdFusion Structure
Just a quick reference on how to loop over a structure without knowing its keys.
<cfset testStruct = structnew() /> <cfset testStruct.key1 = "test1" /> <cfset testStruct.key2 = "test2" /> <cfset testStruct.key3 = "test3" /> <cfdump var="#testStruct#" /> <cfloop list="#structKeyList(testStruct)#" index="key"> <cfoutput> Key: #key#, Value: #testStruct[key]# </cfoutput> </cfloop>
