diff --git a/src/main/groovy/grails/plugin/scaffolding/ScaffoldingViewResolver.groovy b/src/main/groovy/grails/plugin/scaffolding/ScaffoldingViewResolver.groovy index 12aa0da..91938af 100644 --- a/src/main/groovy/grails/plugin/scaffolding/ScaffoldingViewResolver.groovy +++ b/src/main/groovy/grails/plugin/scaffolding/ScaffoldingViewResolver.groovy @@ -7,16 +7,12 @@ import grails.util.Environment import groovy.text.GStringTemplateEngine import groovy.text.Template import groovy.transform.CompileStatic -import org.grails.buffer.* +import org.grails.buffer.FastStringWriter import org.grails.web.servlet.mvc.GrailsWebRequest import org.grails.web.servlet.view.GroovyPageView import org.grails.web.servlet.view.GroovyPageViewResolver import org.springframework.context.ResourceLoaderAware -import org.springframework.core.io.ByteArrayResource -import org.springframework.core.io.FileSystemResource -import org.springframework.core.io.Resource -import org.springframework.core.io.ResourceLoader -import org.springframework.core.io.UrlResource +import org.springframework.core.io.* import org.springframework.web.servlet.View import java.util.concurrent.ConcurrentHashMap @@ -27,6 +23,39 @@ import java.util.concurrent.ConcurrentHashMap */ @CompileStatic class ScaffoldingViewResolver extends GroovyPageViewResolver implements ResourceLoaderAware, ModelBuilder { + final Class templateOverridePluginDescriptor + + public ScaffoldingViewResolver() { + this.templateOverridePluginDescriptor = null + } + + /** + * This constructor allows a plugin to override the default templates provided by the Scaffolding + * plugin. The plugin that contains the template override should be configured to load AFTER the + * scaffolding plugin. An example implementation follows: + * + *
+     * {@code
+     * def loadAfter = ['scaffolding']
+     * }
+     * 
+ * ... + *
+     * {@code
+     * @Override
+     * Closure doWithSpring() { { ->
+     *    jspViewResolver(ScaffoldingViewResolver, this.class) { bean ->
+     *        bean.lazyInit = true
+     *        bean.parent = "abstractViewResolver"
+     *    }
+     * }}
+     * 
+ * + * @param templateOverridePluginDescriptor + */ + public ScaffoldingViewResolver(Class templateOverridePluginDescriptor) { + this.templateOverridePluginDescriptor = templateOverridePluginDescriptor + } ResourceLoader resourceLoader protected Map generatedViewCache = new ConcurrentHashMap<>() @@ -43,42 +72,46 @@ class ScaffoldingViewResolver extends GroovyPageViewResolver implements Resource @Override protected View loadView(String viewName, Locale locale) throws Exception { def view = super.loadView(viewName, locale) - if(view == null) { + if (view == null) { String cacheKey = buildCacheKey(viewName) view = generatedViewCache.get(cacheKey) - if(view != null) { + if (view != null) { return view - } - else { + } else { def webR = GrailsWebRequest.lookup() def controllerClass = webR.controllerClass def scaffoldValue = controllerClass?.getPropertyValue("scaffold") - if(scaffoldValue instanceof Class) { + if (scaffoldValue instanceof Class) { def shortViewName = viewName.substring(viewName.lastIndexOf('/') + 1) Resource res = null - if(Environment.isDevelopmentMode()) { + if (Environment.isDevelopmentMode()) { res = new FileSystemResource(new File(BuildSettings.BASE_DIR, "src/main/templates/scaffolding/${shortViewName}.gsp")) } - if(!res?.exists()) { + if (!res?.exists()) { def url = IOUtils.findResourceRelativeToClass(controllerClass.clazz, "/META-INF/templates/scaffolding/${shortViewName}.gsp") res = url ? new UrlResource(url) : null } - if(!res.exists()) { + if (!res.exists() && templateOverridePluginDescriptor) { + def url = IOUtils.findResourceRelativeToClass(templateOverridePluginDescriptor, "/META-INF/templates/scaffolding/${shortViewName}.gsp") + res = url ? new UrlResource(url) : null + } + + if (!res.exists()) { res = resourceLoader.getResource("classpath:META-INF/templates/scaffolding/${shortViewName}.gsp") } - if(res.exists()) { - def model = model((Class)scaffoldValue) + if (res.exists()) { + def model = model((Class) scaffoldValue) def viewGenerator = new GStringTemplateEngine() Template t = viewGenerator.createTemplate(res.URL) def contents = new FastStringWriter() t.make(model.asMap()).writeTo(contents) - + def template = templateEngine.createTemplate(new ByteArrayResource(contents.toString().getBytes(templateEngine.gspEncoding), "view:$cacheKey")) view = new GroovyPageView() view.setServletContext(getServletContext()) @@ -88,8 +121,7 @@ class ScaffoldingViewResolver extends GroovyPageViewResolver implements Resource view.afterPropertiesSet() generatedViewCache.put(cacheKey, view) return view - } - else { + } else { return view }