Index: farcry_core/packages/types/_dmnavigation/edit.cfm
===================================================================
--- farcry_core/packages/types/_dmnavigation/edit.cfm	(.../farcry-2.3)	(revision 16)
+++ farcry_core/packages/types/_dmnavigation/edit.cfm	(.../fuchanges_0-2)	(revision 16)
@@ -81,34 +81,9 @@
 		<!--- get current fu --->
 		<cfset fuUrl = application.factory.oFU.getFU(objectid=stObj.objectid)>
 		
-		<!--- check for suffix --->
-		<cfif listLen(application.config.fusettings.suffix,"/") gt 0 and not listContains(fuUrl,"objectid")>
-			<cfset fuLen = listLen(fuURL,"/") - listLen(application.config.fusettings.suffix,"/")>
-		<cfelse>
-			<cfset fuLen = listLen(fuURL,"/")>
-		</cfif>
-		
 		<!--- check if new object --->
-		<cfif listContains(fuUrl,"objectid")>
-			<!--- get ancestors --->
-			<cfset qAncestors = request.factory.oTree.getAncestors(objectid=stobj.objectid,bIncludeSelf=false)>
-			<!--- remove root & home --->
-			<cfquery dbtype="query" name="qCrumb">
-				SELECT objectName FROM qAncestors
-				WHERE nLevel >= 2
-				ORDER BY nLevel
-			</cfquery>				
-			<!--- join titles together --->
-			<cfset breadCrumb = valueList(qCrumb.objectname)>
-			<!--- change delimiter --->
-			<cfset breadCrumb = listChangeDelims(breadCrumb,"/",",")>				
-			<!--- append new title --->
-			<cfset breadCrumb = listAppend(breadCrumb,form.title,"/")>				
-			
-			<!--- set new fu --->
-			<cfset fuUrl = application.config.fusettings.urlpattern&breadcrumb&application.config.fusettings.suffix>
-			<!--- set fu --->
-			<cfset application.factory.oFU.setFU(objectid=stobj.objectid,alias=lcase(fuUrl))>
+		<cfif not application.factory.oFU.hasFU(objectid=stObj.objectID)>
+         <cfset application.factory.oFU.createAndSetFUAlias(objectid=stObj.objectID) />
 		<cfelse>
 			<!--- delete current fu --->
 			<cfset application.factory.oFU.deleteFu(fuUrl)>
@@ -120,37 +95,17 @@
 					<cfset descfuUrl = application.factory.oFU.getFU(objectid=qGetDescendants.objectid)>
 					<!--- check if descendants have fus set --->
 					<cfif listContains(descfuUrl,"objectid")>
-						<!--- get ancestors --->
-						<cfset qAncestors = request.factory.oTree.getAncestors(objectid=qGetDescendants.objectid,bIncludeSelf=true)>
-						<!--- remove root & home --->
-						<cfquery dbtype="query" name="qCrumb">
-							SELECT objectName FROM qAncestors
-							WHERE nLevel >= 2
-							ORDER BY nLevel
-						</cfquery>
-						<!--- join titles together --->
-						<cfset breadCrumb = valueList(qCrumb.objectname)>
-						<!--- change delimiter --->
-						<cfset breadCrumb = listChangeDelims(breadCrumb,"/",",")>
-						<!--- set new fu for descendant --->
-						<cfset newFu = application.config.fusettings.urlpattern&breadcrumb&application.config.fusettings.suffix>
 						<!--- set fu for descendant --->
-						<cfset application.factory.oFU.setFU(objectid=qGetDescendants.objectid,alias=lcase(newFu))>
+						<cfset application.factory.oFU.createAndSetFUAlias(objectid=qGetDescendants.objectid)>
 					<cfelse>
 						<!--- delete current fu for descendant --->
 						<cfset application.factory.oFU.deleteFu(descfuUrl)>
-						<!--- work out new fu for descendant  --->
-						<cfset newfu = listSetAt(descfuUrl,fuLen,form.title,"/")>
-						<!--- set new fu  for descendant --->
-						<cfset application.factory.oFU.setFu(objectid=qGetDescendants.objectid,alias=lcase(newfu))>
+						<cfset application.factory.oFU.createAndSetFUAlias(objectid=qGetDescendants.objectid)>
 					</cfif>
 				</cfloop>
-			</cfif>
-			
-			<!--- work out new fu for actual object--->
-			<cfset newfu = listSetAt(fuUrl,fuLen,form.title,"/")>
+			</cfif>		
 			<!--- set fu for actual object --->
-			<cfset application.factory.oFU.setFU(objectid=stobj.objectid,alias=lcase(newfu))>
+			<cfset application.factory.oFU.createAndSetFUAlias(objectid=stobj.objectid)>
 		</cfif> 
 	</cfif>
 	
@@ -215,6 +170,10 @@
 							<td nowrap><span class="FormLabel">#application.adminBundle[session.dmProfile.locale].navAliases#</span></td>
 							<td nowrap><input type="text" name="lNavIDAlias" value="#stObj.lNavIDAlias#" class="FormTextBox"></td>
 						</tr>
+						<tr valign="top">
+							<td nowrap><span class="FormLabel">Friendly URL:</span></td>
+							<td nowrap><input type="text" name="fu" value="#stObj.fu#" class="FormTextBox"></td>
+						</tr>
 						</table>
 						</display:OpenLayer>
 					</div>
Index: farcry_core/packages/types/dmNavigation.cfc
===================================================================
--- farcry_core/packages/types/dmNavigation.cfc	(.../farcry-2.3)	(revision 16)
+++ farcry_core/packages/types/dmNavigation.cfc	(.../fuchanges_0-2)	(revision 16)
@@ -32,6 +32,7 @@
 <cfproperty name="lNavIDAlias" type="string" hint="A Nav alias provides a human interpretable link to this navigation node.  Each Nav alias is set up as key in the structure application.navalias.<i>aliasname</i> with a value equal to the navigation node's UUID." required="no" default="">
 <cfproperty name="options" type="string" hint="No idea what this is for." required="no" default="">
 <cfproperty name="status" type="string" hint="Status of the node (draft, pending, approved)." required="yes" default="draft">
+<cfproperty name="fu" type="string" hint="Friendly URL for this node." required="no" default="">
 
 <!------------------------------------------------------------------------
 object methods 
Index: farcry_core/packages/farcry/fu.cfc
===================================================================
--- farcry_core/packages/farcry/fu.cfc	(.../farcry-2.3)	(revision 16)
+++ farcry_core/packages/farcry/fu.cfc	(.../fuchanges_0-2)	(revision 16)
@@ -131,7 +131,7 @@
 		<cfreturn true>
 	</cffunction>
 	
-	<cffunction name="updateAppScope" access="public" hint="Updates the application scope with the FU mappings" output="yes">
+	<cffunction name="updateAppScope" access="public" hint="Updates the application scope with the FU mappings" output="No">
 		<cfset var stMappings = getMappings()>
 		<cfset var stTemp = structCopy(stMappings)>
 		<!--- loop over all mappings and remove any from other sites --->
@@ -144,41 +144,75 @@
 		<cfset application.FU.mappings = stTemp>
 	</cffunction>
 
-	<cffunction name="createFUAlias" access="public" returntype="string" hint="Creates the FU Alias for a given objectid">
+	<cffunction name="createFUAlias" access="public" returntype="string" hint="Creates the FU Alias for a given objectid" output="No">
 		<cfargument name="objectid" required="Yes">
 		
 		<cfset var qCrumb = "">
 		<cfset var breadCrumb = "">
 		<cfset var qAncestors = request.factory.oTree.getAncestors(objectid=arguments.objectid,bIncludeSelf=true)>
-		
+		<cfset var oNav = createObject("component",application.types.dmNavigation.typepath)>
+		<cfset var qAllNavs = 0>
+		<cfset var i = 0>
+		<cfset var qTempNav = 0>
 		<!--- remove root & home --->
 		<cfquery dbtype="query" name="qCrumb">
-			SELECT objectName FROM qAncestors
+			SELECT objectName, objectID FROM qAncestors
 			WHERE nLevel >= 2
 			ORDER BY nLevel
 		</cfquery>
-		<cfscript>
-			// join titles together 
-			breadCrumb = lcase(valueList(qCrumb.objectname));
-			// change delimiter 
-			breadCrumb = listChangeDelims(breadCrumb,"/",",");
-			// remove spaces 
-			breadCrumb = replace(breadCrumb,' ','-',"all");
-			// prepend fu url pattern and add suffix
-			breadCrumb = application.config.fusettings.urlpattern & breadcrumb & application.config.fusettings.suffix;
-		</cfscript>	
-	<cfreturn breadcrumb>	
+		<cfif qCrumb.recordCount eq 0>
+		   <cfreturn "" />
+		</cfif>
+		<!--- optimisation: get all dmnavgiation data to avoid a getData() call --->
+		<cfquery name="qAllNavs" datasource="#application.dsn#">
+		   SELECT objectid, fu from #application.dbowner#dmNavigation
+		</cfquery>
+		<!--- collect fu labels if the object has any, otherwise just use objectname --->
+		<cfloop from="1" to="#qCrumb.recordCount#" index="i">
+		   <cfquery dbtype="query" name="qTempNav">
+		      SELECT fu FROM qAllNavs
+		      WHERE objectid = '#qCrumb.objectID[i]#'
+		   </cfquery>
+		   <cfif len(trim(qTempNav.fu[1]))>
+		      <cfset breadcrumb = listAppend(breadcrumb,lcase(trim(qTempNav.fu[1]))) />
+		   <cfelse>
+		      <cfset breadcrumb = listAppend(breadcrumb,lcase(qCrumb.objectname[i])) />
+		   </cfif>
+		</cfloop>
+		<!--- change delimiter --->
+		<cfset breadCrumb = listChangeDelims(breadCrumb,"/",",") />
+		<!--- remove spaces --->
+		<cfset breadCrumb = replace(breadCrumb,' ','-',"all") />
+		<!--- prepend fu url pattern and add suffix --->
+		<cfset breadCrumb = application.config.fusettings.urlpattern
+		                    & breadcrumb & application.config.fusettings.suffix />
+   	<cfreturn breadcrumb>	
 	</cffunction>	
 	
+	<cffunction name="createAndSetFUAlias" access="public" returntype="string" hint="Creates and sets an the FU mapping for a given dmNavigation object. Returns the generated friendly URL." output="No">
+	   <cfargument name="objectid" required="true" hint="The objectid of the dmNavigation node" />
+      <cfset var breadCrumb = "">
+      <cfif arguments.objectid eq application.navid.home>
+         <cfset breadcrumb = application.config.fusettings.urlpattern />
+      <cfelse>
+         <cfset breadcrumb = createFUAlias(objectid=arguments.objectid) />
+      </cfif>
+      <cfif breadCrumb neq "">
+			<cfset setFU(objectid=arguments.objectid,alias=breadcrumb) />
+      </cfif>
+      <cfreturn breadCrumb />
+	</cffunction>
 	
-	<cffunction name="createAll" access="public" returntype="boolean" hint="Deletes old mappings and creates new entries for entire tree, and writes the map file to disk" output="yes">
+	<cffunction name="createAll" access="public" returntype="boolean" hint="Deletes old mappings and creates new entries for entire tree, and writes the map file to disk" output="No">
 		
 		<!--- get nav tree --->
 		<cfset var qNav = request.factory.oTree.getDescendants(objectid=application.navid.home, depth=50)>
 		<cfset var qAncestors = "">
 		<cfset var qCrumb = "">
 		<cfset var breadCrumb = "">
-				
+		<cfset var oNav = createObject("component",application.types.dmNavigation.typepath)>
+		<cfset var i = 0>
+
 		<!--- remove existing fu's --->
 		<cfset deleteALL()>
 		<!--- set error template --->		
@@ -187,29 +221,12 @@
 		<cfset setURLVar("nav")>
 		<!--- loop over nav tree and create friendly urls --->
 		<cfloop query="qNav">
-			<!--- get ancestors of object --->
-			<cfset qAncestors = request.factory.oTree.getAncestors(objectid=objectid,bIncludeSelf=true)>
-			<!--- remove root & home --->
-			<cfquery dbtype="query" name="qCrumb">
-				SELECT objectName FROM qAncestors
-				WHERE nLevel >= 2
-				ORDER BY nLevel
-			</cfquery>
-			<cfif val(qCrumb.recordcount)>
-				<!--- join titles together --->
-				<cfset breadCrumb = lcase(valueList(qCrumb.objectname))>
-				<!--- change delimiter --->
-				<cfset breadCrumb = listChangeDelims(breadCrumb,"/",",")>
-				<!--- remove spaces --->
-				<cfset breadCrumb = replace(breadCrumb,' ','-',"all") & application.config.fusettings.suffix>
-				<!--- create fu --->
-				<cfset setFU(objectid=objectid,alias=application.config.fusettings.urlpattern&breadcrumb)>
-			</cfif>
+         <cfset createAndSetFUAlias(objectid=qNav.objectid) />
 		</cfloop>
 		<!--- create fu for home--->
-		<cfset setFU(objectid=application.navid.home,alias=application.config.fusettings.urlpattern)>
-		<cfset updateAppScope()>
-		<cfreturn true>
+		<cfset createAndSetFUAlias(objectid=application.navid.home) />
+		<cfset updateAppScope() />
+		<cfreturn true />
 	</cffunction>
 	
 	<cffunction name="setFU" access="public" returntype="string" hint="Sets an fu" output="No">
@@ -261,5 +278,12 @@
 			return fuURL;
 		</cfscript>
 	</cffunction>
+	
+	<cffunction name="hasFU" access="public" returntype="boolean" hint="Returns whether an FU has been set for the given objectid" output="No">
+	   <cfargument name="objectid" required="yes" hint="Objectid of object" />
+	   <cfset var fu = getFU(objectid=arguments.objectid) />
+	   <!--- if getFU() returned a string containing "objectid" then we should return false --->
+	   <cfreturn not listContains(fu,"objectid") />
+	</cffunction>
 
 </cfcomponent>
\ No newline at end of file
