From 2ecfd6b17a435b71665379cdf57260f900596b21 Mon Sep 17 00:00:00 2001 From: Michael Rigsby Date: Sat, 21 Mar 2026 14:21:25 -0400 Subject: [PATCH] Generic ColdBox View Helper Initial commit --- helpers/helpers.cfm | 24 +++++++++ test-harness/handlers/Main.cfc | 26 ++++++++++ test-harness/tests/specs/CBWIRESpec.cfc | 49 +++++++++++++++++-- .../genericWireViewTesting/genericTest.cfm | 22 +++++++++ views/genericWireView.cfm | 15 ++++++ 5 files changed, 131 insertions(+), 5 deletions(-) create mode 100644 test-harness/wires/genericWireViewTesting/genericTest.cfm create mode 100644 views/genericWireView.cfm diff --git a/helpers/helpers.cfm b/helpers/helpers.cfm index 3a555f98..5f683c97 100644 --- a/helpers/helpers.cfm +++ b/helpers/helpers.cfm @@ -36,4 +36,28 @@ function wire(required string name, struct params = {}, string key = "", lazy, boolean lazyIsolated = true ) { return getInstance("CBWIREController@cbwire").wire( argumentCollection=arguments ); } + + /** + * A helper function to set up the view arguments and call the generic wire view. + * Eliminates the need to manually create a basic view that would usually only contains a + * title (optional) and the wire() method call with the appropriate arguments. + * + * @wireName string | The name of the wire component to render. Required. + * @wireParams struct | The parameters to pass to the wire component. Optional, defaults to an empty struct. + * @viewArgs struct | Additional arguments to pass to the view. Optional, defaults to an empty struct. + * @viewArgs.title string | An optional title to display above the wire component in the view. { "title" : "My Cool Page Title" } + * @viewArgs.titleTag string | An optional HTML tag to wrap the title in. Defaults to h1 if title is provided without a titleTag. { "titleTag" : "h2" } + * + * @return void | Sets the events view to the generic wire view with the appropriate arguments. + */ + function wireGenericView( required string wireName, struct wireParams = {}, struct viewArgs={} ) { + // init event if not available in the current context and scope it to this method + if( isNull( event ) ){ + var event = wirebox.getInstance( "coldbox:requestContext" ); + } + // append wire name and params to view args so they can be used in the view + viewArgs._wireName = wireName; + viewArgs._wireParams = wireParams; + event.setView( view = "genericWireView", module="cbwire", args = viewArgs ); + } diff --git a/test-harness/handlers/Main.cfc b/test-harness/handlers/Main.cfc index b9b4e772..3c068555 100644 --- a/test-harness/handlers/Main.cfc +++ b/test-harness/handlers/Main.cfc @@ -8,6 +8,32 @@ component { event.setView( "main/index" ); } + any function testGenericWireView1( event, rc, prc ){ + /* + Bypass the need for a view and just call the wireGenericView() helper directly in the handler method + this will render the specified component in the generic wire view and pass the title and titleTag + arguments to it as well + */ + wireGenericView( + "genericWireViewTesting.genericTest", + {}, + { title = "CBWIRE Test wireGenericView() Helper One", titleTag = "h2" } + ); + } + + any function testGenericWireView2( event, rc, prc ){ + /* + Bypass the need for a view and just call the wireGenericView() helper directly in the handler method + this will render the specified component in the generic wire view and pass the title and titleTag + arguments to it as well + */ + wireGenericView( + "genericWireViewTesting.genericTest", + { "testArgument" : "Test Argument Passed In Succesfully" }, + { title = "CBWIRE Test wireGenericView() Helper Two", titleTag = "h3" } + ); + } + // Run on first init any function onAppInit( event, rc, prc ){ } diff --git a/test-harness/tests/specs/CBWIRESpec.cfc b/test-harness/tests/specs/CBWIRESpec.cfc index 5c5aafe6..7ebf0663 100644 --- a/test-harness/tests/specs/CBWIRESpec.cfc +++ b/test-harness/tests/specs/CBWIRESpec.cfc @@ -127,6 +127,45 @@ component extends="coldbox.system.testing.BaseTestCase" { expect( beforeHead ).toInclude( "" ); } ); + it( "should use wireGenericView() to set the event view to view=genericWireView & module=cbwire (without wire params)", function() { + + var event = this.get( "Main.testGenericWireView1" ); + var prc = event.getPrivateContext(); + var html = event.getRenderedContent(); + // validate view and module were set properly by wireGenericView() helper + expect( prc.currentView ).toBe( "genericWireView" ); + expect( prc.viewModule ).toBe( "cbwire" ); + expect( prc.currentViewArgs._WIRENAME ).toBe( "genericWireViewTesting.genericTest" ); + // validate custom title tags + expect( html ).toInclude( "

" ); + expect( html ).toInclude( "

" ); + // validate custom title + expect( html ).toInclude( "CBWIRE Test wireGenericView() Helper One" ); + // validate that the wire component rendered in the view + expect( html ).toInclude( "Generic Wire View Test Component" ); + expect( html ).toInclude( "No Test Argument Passed" ); + } ); + + it( "should use wireGenericView() to set the event view to view=genericWireView & module=cbwire (with wire params)", function() { + + var event = this.get( "Main.testGenericWireView2" ); + var prc = event.getPrivateContext(); + var html = event.getRenderedContent(); + // validate view and module were set properly by wireGenericView() helper + expect( prc.currentView ).toBe( "genericWireView" ); + expect( prc.viewModule ).toBe( "cbwire" ); + expect( prc.currentViewArgs._WIRENAME ).toBe( "genericWireViewTesting.genericTest" ); + // validate custom title tags + expect( html ).toInclude( "

" ); + expect( html ).toInclude( "

" ); + // validate custom title + expect( html ).toInclude( "CBWIRE Test wireGenericView() Helper Two" ); + // validate that the wire component rendered in the view + expect( html ).toInclude( "Generic Wire View Test Component" ); + expect( html ).toInclude( "Test Argument Passed In Succesfully" ); + } ); + + } ); describe("Component.cfc", function() { @@ -727,7 +766,7 @@ component extends="coldbox.system.testing.BaseTestCase" { var settings = getInstance( "coldbox:modulesettings:cbwire" ); var originalSetting = settings.csrfEnabled; settings.csrfEnabled = false; - + var payload = incomingRequest( memo = { "name": "TestComponent", @@ -747,12 +786,12 @@ component extends="coldbox.system.testing.BaseTestCase" { updates = {}, csrfToken = "badToken" ); - + // Should not throw an error even with bad token when CSRF is disabled var response = cbwireController.handleRequest( payload, event ); expect( isStruct( response ) ).toBeTrue(); expect( response.components[1].effects.html ).toInclude( "CBWIRE Slays!" ); - + // Restore original setting settings.csrfEnabled = originalSetting; } ); @@ -761,10 +800,10 @@ component extends="coldbox.system.testing.BaseTestCase" { var settings = getInstance( "coldbox:modulesettings:cbwire" ); var originalSetting = settings.csrfEnabled; settings.csrfEnabled = false; - + var token = cbwireController.generateCSRFToken(); expect( token ).toBe( "" ); - + // Restore original setting settings.csrfEnabled = originalSetting; } ); diff --git a/test-harness/wires/genericWireViewTesting/genericTest.cfm b/test-harness/wires/genericWireViewTesting/genericTest.cfm new file mode 100644 index 00000000..20f41a49 --- /dev/null +++ b/test-harness/wires/genericWireViewTesting/genericTest.cfm @@ -0,0 +1,22 @@ + + //@startWire + + data = { + "title": "Generic Wire View Test Component", + "testArgument": "No Test Argument Passed" + } + + function onMount( event, rc, prc, params ){ + if( structKeyExists( params, "testArgument" ) ){ + data.testArgument = params.testArgument; + } + } + //@endWire + + + +
+ Title: #title#
+ Test Argument: #testArgument# +
+
\ No newline at end of file diff --git a/views/genericWireView.cfm b/views/genericWireView.cfm new file mode 100644 index 00000000..3fb68f67 --- /dev/null +++ b/views/genericWireView.cfm @@ -0,0 +1,15 @@ + + + + #args.keyExists( "titleTag" ) && len( args.titleTag ) ? "<" & args.titleTag & ">" : "

"# + #args.title# + #args.keyExists( "titleTag" ) && len( args.titleTag ) ? "" : "

"# +
+ #wire( name=args._wireName, params=args._wireParams )# + +

+ No wire component name specified for wireGenericView() method!
+ Please provide a valid component name as the first argument when calling this method. +

+
+
\ No newline at end of file