diff --git a/models/Component.cfc b/models/Component.cfc index 606bf24..40987b7 100644 --- a/models/Component.cfc +++ b/models/Component.cfc @@ -81,6 +81,7 @@ component output="true" accessors="true" { variables._redirect = ""; variables._redirectUsingNavigate = false; variables._isolate = false; + variables._path = ""; variables._renderedContent = ""; variables._scripts = [:]; variables._assets = [:]; @@ -229,7 +230,7 @@ component output="true" accessors="true" { */ function template( viewPath, params = {} ) { // Normalize the view path - local.normalizedPath = variables._renderService.normalizeViewPath( arguments.viewPath ); + local.normalizedPath = variables._renderService.normalizeViewPath( arguments.viewPath, variables._path ); // Render the view content and trim the result return variables._renderService.renderViewContent( this, local.normalizedPath, arguments.params ); } @@ -360,7 +361,7 @@ component output="true" accessors="true" { // Determine if component should be lazy loaded // If lazy parameter is explicitly provided, use that value // Otherwise, use the component's lazy preference - local.shouldLazyLoad = isNull( arguments.lazy ) ? + local.shouldLazyLoad = isNull( arguments.lazy ) ? local.instance._getLazyLoad() : // Use component's preference if no explicit parameter arguments.lazy; // Use explicit parameter value diff --git a/models/services/RenderService.cfc b/models/services/RenderService.cfc index e1e5280..5e5dd20 100644 --- a/models/services/RenderService.cfc +++ b/models/services/RenderService.cfc @@ -67,7 +67,7 @@ component accessors="true" singleton { wire.set_renderedContent( local.viewContent ); return local.viewContent; - } + } return wire.get_renderedContent(); } @@ -164,14 +164,15 @@ component accessors="true" singleton { } /** - * Normalizes the view path for rendering. This means it will convert the dot notation path + * Normalizes the view path for rendering. This means it will convert the dot notation path * to a slash notation path, check for the existence of .bxm or .cfm files, and ensure the path is correctly formatted. * * @viewPath string | The dot notation path to the view template to be rendered, without the .cfm extension. + * @componentPath string | The component path, used to determine if the normalized path should be prefixed with "wires/". * * @return string */ - function normalizeViewPath( required viewPath ) { + function normalizeViewPath( required viewPath, required componentPath ) { var paths = buildViewPaths( arguments.viewPath ); if ( paths.normalizedPath contains "cbwire/models/tmp/" ) { @@ -190,7 +191,7 @@ component accessors="true" singleton { throw( type="CBWIREException", message="A .bxm or .cfm template could not be found for '#arguments.viewPath#'." ); } - if ( left( paths.normalizedPath, 6 ) != "wires/" ) { + if ( !isNull( arguments.componentPath ) && !find( "@", arguments.componentPath ) && left( paths.normalizedPath, 6 ) != "wires/" ) { paths.normalizedPath = "wires/" & paths.normalizedPath; } if ( left( paths.normalizedPath, 1 ) != "/" ) { diff --git a/test-harness/modules_app/testingmodule/wires/twoFileModuleComponent.cfc b/test-harness/modules_app/testingmodule/wires/twoFileModuleComponent.cfc new file mode 100644 index 0000000..2413d42 --- /dev/null +++ b/test-harness/modules_app/testingmodule/wires/twoFileModuleComponent.cfc @@ -0,0 +1,8 @@ +component extends="cbwire.models.Component" { + + + data = { + "myDataPropKey" : "My Data Prop Value" + }; + +} diff --git a/test-harness/modules_app/testingmodule/wires/twoFileModuleComponent.cfm b/test-harness/modules_app/testingmodule/wires/twoFileModuleComponent.cfm new file mode 100644 index 0000000..cfafbc1 --- /dev/null +++ b/test-harness/modules_app/testingmodule/wires/twoFileModuleComponent.cfm @@ -0,0 +1,9 @@ + +
+ +

Good Morning and hello CBWire Developer from a two file wire in a module!

+ +

Good Afternoon and hello CBWire Developer from a two file wire in a module!

+
+
+
\ No newline at end of file diff --git a/test-harness/tests/specs/CBWIRESpec.cfc b/test-harness/tests/specs/CBWIRESpec.cfc index 5c5aafe..287b35f 100644 --- a/test-harness/tests/specs/CBWIRESpec.cfc +++ b/test-harness/tests/specs/CBWIRESpec.cfc @@ -727,7 +727,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 +747,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 +761,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; } ); @@ -1819,11 +1819,16 @@ component extends="coldbox.system.testing.BaseTestCase" { } ).toThrow( type="ModuleNotFound" ); } ); - it( "should render component from module using default wires location", function() { + it( "should render single file component from module using default wires location", function() { var result = cbwireController.wire( "NestedModuleDefaultComponent@testingmodule" ); expect( result ).toContain( "Nested module component using default wires location" ); } ); + it( "should render a two file component from module using default wires location", function() { + var result = cbwireController.wire( "twoFileModuleComponent@testingmodule" ); + expect( result ).toContain( "hello CBWire Developer from a two file wire in a module" ); + } ); + it( "should render component from module using nested folder", function() { var result = cbwireController.wire( "wires.nestedComponent.NestedFolderComponent@testingmodule" ); expect( result ).toContain( "Nested folder component" ); diff --git a/test-harness/tests/specs/unit/services/RenderServiceSpec.cfc b/test-harness/tests/specs/unit/services/RenderServiceSpec.cfc index 499efcf..a898222 100644 --- a/test-harness/tests/specs/unit/services/RenderServiceSpec.cfc +++ b/test-harness/tests/specs/unit/services/RenderServiceSpec.cfc @@ -1,13 +1,13 @@ component extends="coldbox.system.testing.BaseTestCase" { - + function beforeAll() { variables.mockController = createStub(); variables.mockUtility = createStub(); variables.mockChecksumService = createStub(); variables.mockValidationService = createStub(); variables.mockRequestService = createStub(); - + variables.renderService = prepareMock( new cbwire.models.services.RenderService() ); renderService.setCBWIREController( mockController ); renderService.setUtilityService( mockUtility ); @@ -263,6 +263,8 @@ component extends="coldbox.system.testing.BaseTestCase" { it( "should return .bxm path when .bxm file exists", function() { var input = "my.view.template"; + // simulate the components variables._path which is what is passed to the wire() method + var componentPath = "my.view.template"; var bxmAbsolutePath = expandPath( "/my/view/template.bxm" ); var cfmAbsolutePath = expandPath( "/my/view/template.cfm" ); var expectedPath = "/wires/my/view/template.bxm"; @@ -270,12 +272,14 @@ component extends="coldbox.system.testing.BaseTestCase" { mockUtility.$( "fileExists" ).$args( bxmAbsolutePath ).$results( true ); mockUtility.$( "fileExists" ).$args( cfmAbsolutePath ).$results( false ); - var result = renderService.normalizeViewPath( input ); + var result = renderService.normalizeViewPath( input, componentPath ); expect( result ).toBe( expectedPath ); }); it( "should return .cfm path when only .cfm file exists", function() { var input = "my.view.template"; + // simulate the components variables._path which is what is passed to the wire() method + var component_path = "my.view.template"; var bxmAbsolutePath = expandPath( "/my/view/template.bxm" ); var cfmAbsolutePath = expandPath( "/my/view/template.cfm" ); var expectedPath = "/wires/my/view/template.cfm"; @@ -283,12 +287,31 @@ component extends="coldbox.system.testing.BaseTestCase" { mockUtility.$( "fileExists" ).$args( bxmAbsolutePath ).$results( false ); mockUtility.$( "fileExists" ).$args( cfmAbsolutePath ).$results( true ); - var result = renderService.normalizeViewPath( input ); + var result = renderService.normalizeViewPath( input, component_path ); + expect( result ).toBe( expectedPath ); + }); + + it( "should return .cfm module path when wire is located in module wires directory", function() { + var input = "modules_app.testingmodule.wires.twoFileModuleComponent"; + // simulate the components variables._path which is what is passed to the wire() method + var component_path = "twoFileModuleComponent@testingmodule"; + // use full path to module wire + var bxmAbsolutePath = expandPath( "../modules_app/testingmodule/wires/twoFileModuleComponent.bxm" ); + var cfmAbsolutePath = expandPath( "../modules_app/testingmodule/wires/twoFileModuleComponent.cfm" ); + + var expectedPath = "/modules_app/testingmodule/wires/twoFileModuleComponent.cfm"; + // mock the file exists calls for both .bxm and .cfm paths + mockUtility.$( "fileExists" ).$args( bxmAbsolutePath ).$results( false ); + mockUtility.$( "fileExists" ).$args( cfmAbsolutePath ).$results( true ); + + var result = renderService.normalizeViewPath( input, component_path ); expect( result ).toBe( expectedPath ); }); it( "should throw when neither .bxm nor .cfm exists", function() { var input = "my.view.template"; + // simulate the components variables._path which is what is passed to the wire() method + var component_path = "my.view.template"; var bxmAbsolutePath = expandPath( "/nonexistent/view.bxm" ); var cfmAbsolutePath = expandPath( "/nonexistent/view.cfm" ); var expectedPath = "/wires/my/view/template.cfm"; @@ -297,29 +320,34 @@ component extends="coldbox.system.testing.BaseTestCase" { mockUtility.$( "fileExists" ).$args( cfmAbsolutePath ).$results( false ); expect( function() { - renderService.normalizeViewPath( "nonexistent.view" ); + renderService.normalizeViewPath( "nonexistent.view", component_path ); }).toThrow( "CBWIREException" ); }); it( "should return path with .bxm for tmp path when .bxm exists", function() { var input = "cbwire.models.tmp.componentName"; + // simulate the components variables._path which is what is passed to the wire() method + var component_path = "cbwire.models.tmp.componentName"; mockUtility.$( "fileExists" ).$args( expandPath( "/cbwire/models/tmp/componentName.bxm" ) ).$results( true ); mockUtility.$( "fileExists" ).$args( expandPath( "/cbwire/models/tmp/componentName.cfm" ) ).$results( false ); - var result = renderService.normalizeViewPath( input ); + var result = renderService.normalizeViewPath( input, component_path ); expect( result ).toBe( "/cbwire/models/tmp/componentName.bxm" ); }); it( "should return path with .cfm for tmp path when .cfm exists", function() { var input = "cbwire.models.tmp.componentName"; + // simulate the components variables._path which is what is passed to the wire() method + var component_path = "cbwire.models.tmp.componentName"; mockUtility.$( "fileExists" ).$args( expandPath( "/cbwire/models/tmp/componentName.bxm" ) ).$results( false ); mockUtility.$( "fileExists" ).$args( expandPath( "/cbwire/models/tmp/componentName.cfm" ) ).$results( true ); - var result = renderService.normalizeViewPath( input ); + var result = renderService.normalizeViewPath( input, component_path ); expect( result ).toBe( "/cbwire/models/tmp/componentName.cfm" ); }); + }); describe( "getTemplatePath()", function() {