I'm wondering if anyone has come up with a clean way to generate a breadcrumbs trail in Fusebox. Specifically, is there a way of keeping track of "where you are" and having that somehow generate the breadcrumbs for you? So, for example, if you're executing
/index.cfm?fuseaction=Widgets.ViewWidget&widget=1
and the circuit structure is something like /foo/bar/widgets/
then somehow the system automatically creates an array like:
[
{ title: 'Foo', url: '#self#?fuseaction=Foo.Main' },
{ title: 'Bar', url: '#self#?fuseaction=Bar.Main' },
{ title: 'Widgets', url: '#self#?fuseaction=Widgets.Main' },
{ title: 'Awesome Widget', url: '' }
]
Which can then be rendered as
Foo > Bar > Widgets > Awesome Widget
Right now it seems the only way to really do this is to create the structure for each fuseaction in a fuse of some kind (either the display fuse or a fuse ded开发者_开发问答icated to creating the crumbtrail).
I'm working with Fusebox for a long time, but still can't understand this part:
circuit structure is something like /foo/bar/widgets/
Any way, once my idea was to use the custom lexicon called "parent" (or anything) for each controller fuseaction, where you put the name of previous level fuseaction.
But as I remember, this method was applicable only when using XML-style circuits, where you can always get any fuseaction info from the global container -- so I didn't make it because of intensive use of no-XMl style.
EDIT: example with lexicon
This will work only with Fusebox 5 traditional.
Let's say we have created following lexicon definition /lexicon/bc/parent.cfm
:
<cfscript>
if (fb_.verbInfo.executionMode is "start") {
// validate fb_.verbInfo.attributes contents
if (not structKeyExists(fb_.verbInfo.attributes,"value")) {
fb_throw("fusebox.badGrammar.requiredAttributeMissing",
"Required attribute is missing",
"The attribute 'value' is required, for a 'parent' verb in fuseaction #fb_.verbInfo.circuit#.#fb_.verbInfo.fuseaction#.");
}
// compile start tag CFML code
circuit = fb_.verbInfo.action.getCircuit().getName();
fa = fb_.verbInfo.action.getCircuit().getFuseactions();
fa[#fb_.verbInfo.fuseaction#].parent = circuit & "." & fb_.verbInfo.attributes.value;
} else {
// compile end tag CFML code
}
</cfscript>
Basically this is copy-pasted standard lexicon tag specially for lexicon parent
.
Assuming we're using Fusebox 5 skeleton example, contoller can look like:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE circuit>
<circuit access="public" xmlns:bc="bc/">
<postfuseaction>
<do action="layout.mainLayout" />
</postfuseaction>
<fuseaction name="welcome" bc:parent="">
<do action="time.getTime" />
<do action="display.sayHello" />
</fuseaction>
<fuseaction name="widgets" bc:parent="app.welcome">
<do action="display.showWidgets" />
</fuseaction>
<fuseaction name="widget" bc:parent="app.widgets">
<do action="display.showWidget" />
</fuseaction>
</circuit>
It shows how the lexicon used for each fuseaction. Please note that if you wont define the attribute bc:parent
it wont appear in custom attributes structure later.
It is possible to use only fuseaction name as parent, if you have all chain within same circuit, it can be easier to use later.
Finally, some quick code to build the stuff. Please see comments, they should be helpful enough.
<!--- path data container with current fuseaction saved --->
<cfset arrBreadcrumbs = [] />
<cfset ArrayAppend(arrBreadcrumbs, attributes.fuseaction) />
<!--- pull the current circuit fuseactions --->
<cfset fuseactions = myFusebox.getApplication().circuits[ListFirst(attributes.fuseaction,'.')].getFuseactions() />
<!--- OR <cfset fuseactions = application.fusebox.circuits[ListFirst(attributes.fuseaction,'.')].getFuseactions()> --->
<!--- pull the current fuseaction custom attributes --->
<cfset fa = ListLast(attributes.fuseaction,'.') />
<cfset customAttributes = fuseactions[fa].getCustomAttributes('bc') />
<!--- save the parent fuseaction name if present -- KEY CHECK IS RECOMMENDED --->
<cfif StructKeyExists(customAttributes, "parent")>
<cfset ArrayPrepend(arrBreadcrumbs, customAttributes.parent) />
</cfif>
<!--- let's say we know that parent is there... --->
<!--- pull the found fuseaction custom attributes --->
<cfset fa = ListLast(customAttributes.parent,'.') />
<cfset customAttributes = fuseactions[fa].getCustomAttributes('bc') />
<!--- save the parent fuseaction name if present --->
<cfif StructKeyExists(customAttributes, "parent")>
<cfset ArrayPrepend(arrBreadcrumbs, customAttributes.parent) />
</cfif>
<!--- render the collected path --->
<cfoutput>
<cfloop index="crumb" from="1" to="#ArrayLen(arrBreadcrumbs)#">
<!--- to have a nice labels you can use another lexicon --->
<a href="#myself##arrBreadcrumbs[crumb]#">#arrBreadcrumbs[crumb]#</a> <cfif crumb LT ArrayLen(arrBreadcrumbs)>></cfif>
</cfloop>
</cfoutput>
So the output should look like this: app.welcome > app.widgets > app.widget
Here's something I use...
act_breadcrum.cfm
=============================
<cfscript>
if (NOT structKeyExists(session, 'clickstream'))
{
session.clickstream = arrayNew(1);
}
</cfscript>
<cflock name="addNewPage" type="exclusive" timeout="10">
<cfscript>
if ((arrayIsEmpty(session.clickstream))
OR (compare(myFusebox.originalCircuit, session.clickstream[arrayLen(session.clickstream)].Circuit))
OR (compare(myFusebox.originalFuseaction, session.clickstream[arrayLen(session.clickstream)].Fuseaction))
)
{
if (arrayLen(session.clickstream) EQ 10)
{
temp = arrayDeleteAt(session.clickstream, 1);
}
temp = arrayAppend(session.clickstream, structNew());
session.clickstream[arrayLen(session.clickstream)].Fuseaction = myFusebox.originalFuseaction;
session.clickstream[arrayLen(session.clickstream)].Circuit = myFusebox.originalCircuit;
}
</cfscript>
</cflock>
dsp_Breadcrum.cfm
==========================
<cfoutput>
<center>
<b><u>Last Clicked</u></b><BR>
<cfloop from="#arrayLen(session.clickstream)#" to="1" index="i" step="-1">
<cfset Opaque=i*.2>
<a href="#Myself##session.clickstream[i].Circuit#.#session.clickstream[i].Fuseaction#" style=opacity:#Opaque#>
#session.clickstream[i].Circuit#
</a><BR>
</cfloop>
</center>
</cfoutput>
精彩评论