diff --git a/application.properties b/application.properties index 7faa260..1145884 100644 --- a/application.properties +++ b/application.properties @@ -1,4 +1,5 @@ #Grails Metadata file -#Sat Apr 06 13:47:56 BST 2013 -app.grails.version=2.2.1 -app.name=angular-scaffolding \ No newline at end of file +#Mon Oct 14 03:48:27 CDT 2013 +app.grails.version=2.3.0 +app.name=angular-scaffolding +app.servlet.version=2.5 diff --git a/grails-app/conf/BuildConfig.groovy b/grails-app/conf/BuildConfig.groovy index c603143..5610438 100644 --- a/grails-app/conf/BuildConfig.groovy +++ b/grails-app/conf/BuildConfig.groovy @@ -22,5 +22,6 @@ grails.project.dependency.resolution = { build(':release:2.2.0', ':rest-client-builder:1.0.2') { export = false } + compile ':scaffolding:2.0.0' } } diff --git a/grails-app/conf/Config.groovy b/grails-app/conf/Config.groovy index e448e67..448e370 100644 --- a/grails-app/conf/Config.groovy +++ b/grails-app/conf/Config.groovy @@ -22,3 +22,27 @@ log4j = { warn 'org.mortbay.log' } + +// Uncomment and edit the following lines to start using Grails encoding & escaping improvements + +/* remove this line +// GSP settings +grails { + views { + gsp { + encoding = 'UTF-8' + htmlcodec = 'xml' // use xml escaping instead of HTML4 escaping + codecs { + expression = 'html' // escapes values inside null + scriptlet = 'none' // escapes output from scriptlets in GSPs + taglib = 'none' // escapes output from taglibs + staticparts = 'none' // escapes output from static template parts + } + } + // escapes all not-encoded output at final stage of outputting + filteringCodecForContentType { + //'text/html' = 'html' + } + } +} +remove this line */ diff --git a/scripts/_NgGenerate.groovy b/scripts/_NgGenerate.groovy index 55734e9..62a5bf3 100644 --- a/scripts/_NgGenerate.groovy +++ b/scripts/_NgGenerate.groovy @@ -1,12 +1,7 @@ import grails.util.GrailsNameUtils -import org.codehaus.groovy.grails.commons.GrailsDomainClass -import org.springframework.core.io.FileSystemResource -import org.springframework.core.io.support.PathMatchingResourcePatternResolver -import org.springframework.util.Assert -import org.codehaus.groovy.grails.scaffolding.* includeTargets << grailsScript("_GrailsCreateArtifacts") -includeTargets << grailsScript("_GrailsGenerate") +includeTargets << new File("scaffoldingPluginDir/scripts/_GrailsGenerate.groovy") includeTargets << grailsScript("_GrailsBootstrap") generateForName = null @@ -37,7 +32,9 @@ target(generateForOne: 'Generates controllers and views for only one domain clas } def generateForDomainClass(domainClass) { - def templateGenerator = new AngularTemplateGenerator(classLoader) + def AngularTemplateGenerator = classLoader.loadClass('grails.plugin.angularscaffolding.AngularTemplateGenerator') + def templateGenerator = AngularTemplateGenerator.newInstance(classLoader) + templateGenerator.grailsApplication = grailsApp templateGenerator.pluginManager = pluginManager templateGenerator.event = event @@ -53,107 +50,3 @@ def generateForDomainClass(domainClass) { event 'GenerateControllerEnd', [domainClass.fullName] } } - -/** - * Can't seem to load this if it's on the plugin source path so I've inlined it here - */ -class AngularTemplateGenerator extends DefaultGrailsTemplateGenerator { - - def event - - AngularTemplateGenerator(ClassLoader classLoader) { - super(classLoader) - } - - def renderEditor = { property, prefix -> - def domainClass = property.domainClass - def cp - if (pluginManager?.hasGrailsPlugin('hibernate')) { - cp = domainClass.constrainedProperties[property.name] - } - - if (!renderEditorTemplate) { - // create template once for performance - def templateText = getTemplateText('renderEditor.template') - renderEditorTemplate = engine.createTemplate(templateText) - } - - def binding = [ - pluginManager: pluginManager, - property: property, - domainClass: domainClass, - cp: cp, - domainInstance: getPropertyName(domainClass), - prefix: prefix - ] - renderEditorTemplate.make(binding).toString() - } - - @Override - void generateViews(GrailsDomainClass domainClass, String destdir) { - Assert.hasText destdir, 'Argument [destdir] not specified' - - for (t in getTemplateNames()) { - event 'StatusUpdate', ["Generating $t for domain class ${domainClass.fullName}"] - generateView domainClass, t, new File(destdir).absolutePath - } - } - - @Override - void generateView(GrailsDomainClass domainClass, String viewName, Writer out) { - def templateText = getTemplateText(viewName) - - if (templateText) { - - def t = engine.createTemplate(templateText) - def multiPart = domainClass.properties.find {it.type == ([] as Byte[]).class || it.type == ([] as byte[]).class} - - boolean hasHibernate = pluginManager?.hasGrailsPlugin('hibernate') - def packageName = domainClass.packageName ? "<%@ page import=\"${domainClass.fullName}\" %>" : "" - def binding = [pluginManager: pluginManager, - packageName: packageName, - domainClass: domainClass, - multiPart: multiPart, - className: domainClass.shortName, - propertyName: getPropertyName(domainClass), - renderEditor: renderEditor, - comparator: hasHibernate ? DomainClassPropertyComparator : SimpleDomainClassPropertyComparator] - - t.make(binding).writeTo(out) - } - } - - @Override - void generateView(GrailsDomainClass domainClass, String viewName, String destDir) { - def suffix = viewName.find(/\.\w+$/) - - def viewsDir = suffix == '.html' ? new File("$destDir/web-app/ng-templates/$domainClass.propertyName") : new File("$destDir/grails-app/views/$domainClass.propertyName") - if (!viewsDir.exists()) viewsDir.mkdirs() - - def destFile = new File(viewsDir, "$viewName") - destFile.withWriter { Writer writer -> - generateView domainClass, viewName, writer - } - } - - @Override - def getTemplateNames() { - def resources = [] - def resolver = new PathMatchingResourcePatternResolver() - def templatesDirPath = "${basedir}/src/templates/scaffolding" - def templatesDir = new FileSystemResource(templatesDirPath) - if (templatesDir.exists()) { - try { - resources.addAll(resolver.getResources("file:$templatesDirPath/*.html").filename) - resources.addAll(resolver.getResources("file:$templatesDirPath/*.gsp").filename) - } catch (e) { - event 'StatusError', ['Error while loading views from grails-app scaffolding folder', e] - } - } - - resources - } - - private String getPropertyName(GrailsDomainClass domainClass) { "${domainClass.propertyName}${domainSuffix}" } - -} diff --git a/src/groovy/grails/plugin/angularscaffolding/AngularTemplateGenerator.groovy b/src/groovy/grails/plugin/angularscaffolding/AngularTemplateGenerator.groovy new file mode 100644 index 0000000..607279a --- /dev/null +++ b/src/groovy/grails/plugin/angularscaffolding/AngularTemplateGenerator.groovy @@ -0,0 +1,112 @@ +package grails.plugin.angularscaffolding + +import org.springframework.util.Assert +import org.codehaus.groovy.grails.commons.GrailsDomainClass +import org.springframework.core.io.FileSystemResource +import org.springframework.core.io.support.PathMatchingResourcePatternResolver +import org.codehaus.groovy.grails.scaffolding.* + +/** + * Can't seem to load this if it's on the plugin source path so I've inlined it here + */ +class AngularTemplateGenerator extends DefaultGrailsTemplateGenerator +{ + def event + + AngularTemplateGenerator(ClassLoader classLoader) { + super(classLoader) + } + + def renderEditor = { property, prefix -> + def domainClass = property.domainClass + def cp + if (pluginManager?.hasGrailsPlugin('hibernate')) { + cp = domainClass.constrainedProperties[property.name] + } + + if (!renderEditorTemplate) { + // create template once for performance + def templateText = getTemplateText('renderEditor.template') + renderEditorTemplate = engine.createTemplate(templateText) + } + + def binding = [ + pluginManager: pluginManager, + property: property, + domainClass: domainClass, + cp: cp, + domainInstance: getPropertyName(domainClass), + prefix: prefix + ] + renderEditorTemplate.make(binding).toString() + } + + @Override + void generateViews(GrailsDomainClass domainClass, String destdir) { + Assert.hasText destdir, 'Argument [destdir] not specified' + + for (t in getTemplateNames()) { + event 'StatusUpdate', ["Generating $t for domain class ${domainClass.fullName}"] + generateView domainClass, t, new File(destdir).absolutePath + } + } + + @Override + void generateView(GrailsDomainClass domainClass, String viewName, Writer out) { + def templateText = getTemplateText(viewName) + + if (templateText) { + + def t = engine.createTemplate(templateText) + def multiPart = domainClass.properties.find {it.type == ([] as Byte[]).class || it.type == ([] as byte[]).class} + + boolean hasHibernate = pluginManager?.hasGrailsPlugin('hibernate') + def packageName = domainClass.packageName ? "<%@ page import=\"${domainClass.fullName}\" %>" : "" + def binding = [pluginManager: pluginManager, + packageName: packageName, + domainClass: domainClass, + multiPart: multiPart, + className: domainClass.shortName, + propertyName: getPropertyName(domainClass), + renderEditor: renderEditor, + comparator: hasHibernate ? DomainClassPropertyComparator : SimpleDomainClassPropertyComparator] + +println "viewName: $viewName, domainClass: $domainClass, class: ${domainClass.class.name}" + t.make(binding).writeTo(out) + } + } + + @Override + void generateView(GrailsDomainClass domainClass, String viewName, String destDir) { + def suffix = viewName.find(/\.\w+$/) + + def viewsDir = suffix == '.html' ? new File("$destDir/web-app/ng-templates/$domainClass.propertyName") : new File("$destDir/grails-app/views/$domainClass.propertyName") + if (!viewsDir.exists()) viewsDir.mkdirs() + + def destFile = new File(viewsDir, "$viewName") + destFile.withWriter { Writer writer -> + generateView domainClass, viewName, writer + } + } + + @Override + protected Set getTemplateNames() { + def resources = [] + def resolver = new PathMatchingResourcePatternResolver() + def templatesDirPath = "${basedir}/src/templates/scaffolding" + def templatesDir = new FileSystemResource(templatesDirPath) + if (templatesDir.exists()) { + try { + resources.addAll(resolver.getResources("file:$templatesDirPath/*.html").filename) + resources.addAll(resolver.getResources("file:$templatesDirPath/*.gsp").filename) + } catch (e) { + event 'StatusError', ['Error while loading views from grails-app scaffolding folder', e] + } + } + + resources as Set + } + + protected String getPropertyName(GrailsDomainClass domainClass) { "${domainClass.propertyName}${domainSuffix}" } + +} diff --git a/src/templates/common/sortable.html b/src/templates/common/sortable.html new file mode 100644 index 0000000..71f6000 --- /dev/null +++ b/src/templates/common/sortable.html @@ -0,0 +1,2 @@ + + diff --git a/src/templates/scaffolding/create.html b/src/templates/scaffolding/create.html index 934735c..9feb3c7 100644 --- a/src/templates/scaffolding/create.html +++ b/src/templates/scaffolding/create.html @@ -6,10 +6,13 @@

Create ${className}

<% excludedProps = Event.allEvents.toList() << 'version' << 'dateCreated' << 'lastUpdated' persistentPropNames = domainClass.persistentProperties*.name - boolean hasHibernate = pluginManager?.hasGrailsPlugin('hibernate') - if (hasHibernate && org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsDomainBinder.getMapping(domainClass)?.identity?.generator == 'assigned') { - persistentPropNames << domainClass.identifier.name - } + boolean hasHibernate = pluginManager?.hasGrailsPlugin('hibernate') || pluginManager?.hasGrailsPlugin('hibernate4') + if (hasHibernate) { + def GrailsDomainBinder = getClass().classLoader.loadClass('org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsDomainBinder') + if (GrailsDomainBinder.newInstance().getMapping(domainClass)?.identity?.generator == 'assigned') { + persistentPropNames << domainClass.identifier.name + } + } props = domainClass.properties.findAll { persistentPropNames.contains(it.name) && !excludedProps.contains(it.name) } Collections.sort(props, comparator.constructors[0].newInstance([domainClass] as Object[])) for (p in props) { diff --git a/src/templates/scaffolding/edit.html b/src/templates/scaffolding/edit.html index 00e19c5..9342186 100644 --- a/src/templates/scaffolding/edit.html +++ b/src/templates/scaffolding/edit.html @@ -8,10 +8,13 @@

Edit ${className}

<% excludedProps = Event.allEvents.toList() << 'version' << 'dateCreated' << 'lastUpdated' persistentPropNames = domainClass.persistentProperties*.name - boolean hasHibernate = pluginManager?.hasGrailsPlugin('hibernate') - if (hasHibernate && org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsDomainBinder.getMapping(domainClass)?.identity?.generator == 'assigned') { - persistentPropNames << domainClass.identifier.name - } + boolean hasHibernate = pluginManager?.hasGrailsPlugin('hibernate') || pluginManager?.hasGrailsPlugin('hibernate4') + if (hasHibernate) { + def GrailsDomainBinder = getClass().classLoader.loadClass('org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsDomainBinder') + if (GrailsDomainBinder.newInstance().getMapping(domainClass)?.identity?.generator == 'assigned') { + persistentPropNames << domainClass.identifier.name + } + } props = domainClass.properties.findAll { persistentPropNames.contains(it.name) && !excludedProps.contains(it.name) } Collections.sort(props, comparator.constructors[0].newInstance([domainClass] as Object[])) for (p in props) { diff --git a/web-app/WEB-INF/applicationContext.xml b/web-app/WEB-INF/applicationContext.xml index 69fbef3..a48dec0 100644 --- a/web-app/WEB-INF/applicationContext.xml +++ b/web-app/WEB-INF/applicationContext.xml @@ -1,8 +1,7 @@ + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> Grails application factory bean @@ -30,4 +29,6 @@ http://www.springframework.org/schema/beans http://www.springframework.org/schem utf-8 + + \ No newline at end of file diff --git a/web-app/WEB-INF/tld/spring.tld b/web-app/WEB-INF/tld/spring.tld index 1bc7091..a0a8c6f 100644 --- a/web-app/WEB-INF/tld/spring.tld +++ b/web-app/WEB-INF/tld/spring.tld @@ -1,311 +1,457 @@ - - - - - - 1.1.1 - - 1.2 - - Spring - + + + + Spring Framework JSP Tag Library + 3.0 + spring http://www.springframework.org/tags - Spring Framework JSP Tag Library. Authors: Rod Johnson, Juergen Hoeller - - - - htmlEscape - org.springframework.web.servlet.tags.HtmlEscapeTag - JSP - Sets default HTML escape value for the current page. Overrides a "defaultHtmlEscape" context-param in web.xml, if any. - + htmlEscape + org.springframework.web.servlet.tags.HtmlEscapeTag + JSP + Set the default value for HTML escaping, to be put + into the current PageContext. defaultHtmlEscape true true - - - - escapeBody - org.springframework.web.servlet.tags.EscapeBodyTag - JSP - Escapes its enclosed body content, applying HTML escaping and/or JavaScript escaping. The HTML escaping flag participates in a page-wide or application-wide setting (i.e. by HtmlEscapeTag or a "defaultHtmlEscape" context-param in web.xml). - + escapeBody + org.springframework.web.servlet.tags.EscapeBodyTag + JSP + Set HTML escaping for this tag, as boolean value. Overrides the + default HTML escaping setting for the current page. htmlEscape false true - + Set JavaScript escaping for this tag, as boolean value. + Default is false. javaScriptEscape false true - - - - message - org.springframework.web.servlet.tags.MessageTag - JSP - Retrieves the message with the given code, or text if code isn't resolvable. The HTML escaping flag participates in a page-wide or application-wide setting (i.e. by HtmlEscapeTag or a "defaultHtmlEscape" context-param in web.xml). - + message + org.springframework.web.servlet.tags.MessageTag + JSP + A MessageSourceResolvable argument (direct or through JSP EL). + Fits nicely when used in conjunction with Spring's own validation error + classes which all implement the MessageSourceResolvable interface. For + example, this allows you to iterate over all of the errors in a form, + passing each error (using a runtime expression) as the value of this + 'message' attribute, thus effecting the easy display of such error + messages. + message + false + true + + + The code (key) to use when looking up the message. + If code is not provided, the text attribute will be used. code false true - + Set optional message arguments for this tag, as a + (comma-)delimited String (each String argument can contain JSP EL), + an Object array (used as argument array), or a single Object (used + as single argument). arguments false true - + The separator character to be used for splitting the + arguments string value; defaults to a 'comma' (','). + argumentSeparator + false + true + + + Default text to output when a message for the given code + could not be found. If both text and code are not set, the tag will + output null. text false true - + The string to use when binding the result to the page, + request, session or application scope. If not specified, the result + gets outputted to the writer (i.e. typically directly to the JSP). var false true - + The scope to use when exporting the result to a variable. + This attribute is only used when var is also set. Possible values are + page, request, session and application. scope false true - + Set HTML escaping for this tag, as boolean value. + Overrides the default HTML escaping setting for the current page. htmlEscape false true - + Set JavaScript escaping for this tag, as boolean value. Default is false. javaScriptEscape false true - - - - theme - org.springframework.web.servlet.tags.ThemeTag - JSP - Retrieves the theme message with the given code, or text if code isn't resolvable. The HTML escaping flag participates in a page-wide or application-wide setting (i.e. by HtmlEscapeTag or a "defaultHtmlEscape" context-param in web.xml). - + theme + org.springframework.web.servlet.tags.ThemeTag + JSP + A MessageSourceResolvable argument (direct or through JSP EL). + message + false + true + + + The code (key) to use when looking up the message. + If code is not provided, the text attribute will be used. code false true - + Set optional message arguments for this tag, as a + (comma-)delimited String (each String argument can contain JSP EL), + an Object array (used as argument array), or a single Object (used + as single argument). arguments false true - + The separator character to be used for splitting the + arguments string value; defaults to a 'comma' (','). + argumentSeparator + false + true + + + Default text to output when a message for the given code + could not be found. If both text and code are not set, the tag will + output null. text false true - + The string to use when binding the result to the page, + request, session or application scope. If not specified, the result + gets outputted to the writer (i.e. typically directly to the JSP). var false true - + The scope to use when exporting the result to a variable. + This attribute is only used when var is also set. Possible values are + page, request, session and application. scope false true - + Set HTML escaping for this tag, as boolean value. + Overrides the default HTML escaping setting for the current page. htmlEscape false true - + Set JavaScript escaping for this tag, as boolean value. Default is false. javaScriptEscape false true - - - - hasBindErrors - org.springframework.web.servlet.tags.BindErrorsTag - JSP - Provides Errors instance in case of bind errors. The HTML escaping flag participates in a page-wide or application-wide setting (i.e. by HtmlEscapeTag or a "defaultHtmlEscape" context-param in web.xml). - + hasBindErrors + org.springframework.web.servlet.tags.BindErrorsTag + JSP errors org.springframework.validation.Errors - + The name of the bean in the request, that needs to be + inspected for errors. If errors are available for this bean, they + will be bound under the 'errors' key. name true true - + Set HTML escaping for this tag, as boolean value. + Overrides the default HTML escaping setting for the current page. htmlEscape false true - - - - nestedPath - org.springframework.web.servlet.tags.NestedPathTag - JSP - Sets a nested path to be used by the bind tag's path. - + nestedPath + org.springframework.web.servlet.tags.NestedPathTag + JSP nestedPath java.lang.String - + Set the path that this tag should apply. E.g. 'customer' + to allow bind paths like 'address.street' rather than + 'customer.address.street'. path true true - - - - bind - org.springframework.web.servlet.tags.BindTag - JSP - Provides BindStatus object for the given bind path. The HTML escaping flag participates in a page-wide or application-wide setting (i.e. by HtmlEscapeTag or a "defaultHtmlEscape" context-param in web.xml). - + bind + org.springframework.web.servlet.tags.BindTag + JSP status org.springframework.web.servlet.support.BindStatus - + The path to the bean or bean property to bind status + information for. For instance account.name, company.address.zipCode + or just employee. The status object will exported to the page scope, + specifically for this bean or bean property path true true - + Set whether to ignore a nested path, if any. Default is to not ignore. ignoreNestedPath false true - + Set HTML escaping for this tag, as boolean value. Overrides + the default HTML escaping setting for the current page. htmlEscape false true - - - - transform - org.springframework.web.servlet.tags.TransformTag - JSP - Provides transformation of variables to Strings, using an appropriate custom PropertyEditor from BindTag (can only be used inside BindTag). The HTML escaping flag participates in a page-wide or application-wide setting - (i.e. by HtmlEscapeTag or a "defaultHtmlEscape" context-param in web.xml). + (i.e. by HtmlEscapeTag or a 'defaultHtmlEscape' context-param in web.xml). - + transform + org.springframework.web.servlet.tags.TransformTag + JSP + The value to transform. This is the actual object you want + to have transformed (for instance a Date). Using the PropertyEditor that + is currently in use by the 'spring:bind' tag. value true true - + The string to use when binding the result to the page, + request, session or application scope. If not specified, the result gets + outputted to the writer (i.e. typically directly to the JSP). var false true - + The scope to use when exported the result to a variable. + This attribute is only used when var is also set. Possible values are + page, request, session and application. scope false true + + Set HTML escaping for this tag, as boolean value. Overrides + the default HTML escaping setting for the current page. + htmlEscape + false + true + + + + URL tag based on the JSTL c:url tag. This variant is fully + backwards compatible with the standard tag. Enhancements include support + for URL template parameters. + url + org.springframework.web.servlet.tags.UrlTag + JSP + + The URL to build. This value can include template place holders + that are replaced with the URL encoded value of the named parameter. Parameters + must be defined using the param tag inside the body of this tag. + value + true + true + + + Specifies a remote application context path. The default is the + current application context path. + context + false + true + + + The name of the variable to export the URL value to. + var + false + true + + The scope for the var. 'application', 'session', 'request' and + 'page' scopes are supported. Defaults to page scope. This attribute has no + effect unless the var attribute is also defined. + scope + false + true + + + Set HTML escaping for this tag, as a boolean value. Overrides the + default HTML escaping setting for the current page. htmlEscape false true + + Set JavaScript escaping for this tag, as a boolean value. + Default is false. + javaScriptEscape + false + true + + + + + Parameter tag based on the JSTL c:param tag. The sole purpose is to + support params inside the spring:url tag. + param + org.springframework.web.servlet.tags.ParamTag + JSP + + The name of the parameter. + name + true + true + + + The value of the parameter. + value + false + true + + + + Evaluates a Spring expression (SpEL) and either prints the result or assigns it to a variable. + eval + org.springframework.web.servlet.tags.EvalTag + JSP + + The expression to evaluate. + expression + true + true + + + The name of the variable to export the evaluation result to. + var + false + true + + + The scope for the var. 'application', 'session', 'request' and + 'page' scopes are supported. Defaults to page scope. This attribute has no + effect unless the var attribute is also defined. + scope + false + true + + + Set HTML escaping for this tag, as a boolean value. Overrides the + default HTML escaping setting for the current page. + htmlEscape + false + true + + + Set JavaScript escaping for this tag, as a boolean value. Default is false. + javaScriptEscape + false + true +