diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml new file mode 100644 index 0000000..38a91ce --- /dev/null +++ b/.github/release-drafter.yml @@ -0,0 +1,134 @@ +name-template: $RESOLVED_VERSION +tag-template: v$RESOLVED_VERSION +pull-request: + title-templates: + fix: '🐛 $TITLE (#$NUMBER)' + feat: '🚀 $TITLE (#$NUMBER)' + default: '$TITLE (#$NUMBER)' +autolabeler: + - label: 'bug' + branch: + - '/fix\/.+/' + title: + - '/fix/i' + - label: 'improvement' + branch: + - '/improv\/.+/' + title: + - '/improv/i' + - label: 'feature' + branch: + - '/feature\/.+/' + title: + - '/feat/i' + - label: 'documentation' + branch: + - '/docs\/.+/' + title: + - '/docs/i' + - label: 'maintenance' + branch: + - '/(chore|refactor|style|test|ci|perf|build)\/.+/' + title: + - '/(chore|refactor|style|test|ci|perf|build)/i' + - label: 'chore' + branch: + - '/chore\/.+/' + title: + - '/chore/i' + - label: 'refactor' + branch: + - '/refactor\/.+/' + title: + - '/refactor/i' + - label: 'style' + branch: + - '/style\/.+/' + title: + - '/style/i' + - label: 'test' + branch: + - '/test\/.+/' + title: + - '/test/i' + - label: 'ci' + branch: + - '/ci\/.+/' + title: + - '/ci/i' + - label: 'perf' + branch: + - '/perf\/.+/' + title: + - '/perf/i' + - label: 'build' + branch: + - '/build\/.+/' + title: + - '/build/i' + - label: 'deps' + branch: + - '/deps\/.+/' + title: + - '/deps/i' + - label: 'revert' + branch: + - '/revert\/.+/' + title: + - '/revert/i' +categories: + - title: '🚀 Features' + labels: + - 'feature' + - "type: enhancement" + - "type: new feature" + - "type: major" + - "type: minor" + - title: '💡 Improvements' + labels: + - 'improvement' + - "type: improvement" + + - title: '🐛 Bug Fixes' + labels: + - 'fix' + - 'bug' + - "type: bug" + - title: '📚 Documentation' + labels: + - 'docs' + - title: '🔧 Maintenance' + labels: + - 'maintenance' + - 'chore' + - 'refactor' + - 'style' + - 'test' + - 'ci' + - 'perf' + - 'build' + - "type: ci" + - "type: build" + - title: '⏪ Reverts' + labels: + - 'revert' +change-template: '- $TITLE @$AUTHOR (#$NUMBER)' +version-resolver: + major: + labels: + - 'type: major' + minor: + labels: + - 'type: minor' + patch: + labels: + - 'type: patch' + default: patch +template: | + ## What's Changed + + $CHANGES + + ## Contributors + + $CONTRIBUTORS \ No newline at end of file diff --git a/.github/renovate.json b/.github/renovate.json new file mode 100644 index 0000000..30740f8 --- /dev/null +++ b/.github/renovate.json @@ -0,0 +1,61 @@ +{ + "extends": [ + "config:base" + ], + "labels": ["type: dependency upgrade"], + "packageRules": [ + { + "matchUpdateTypes": ["major"], + "enabled": false + }, + { + "matchPackagePatterns": ["*"], + "allowedVersions": "!/SNAPSHOT$/" + }, + { + "matchPackagePatterns": [ + "^org\\.codehaus\\.groovy" + ], + "groupName": "groovy monorepo" + }, + { + "matchPackageNames": [ + "org.grails:grails-bom", + "org.grails:grails-bootstrap", + "org.grails:grails-codecs", + "org.grails:grails-console", + "org.grails:grails-core", + "org.grails:grails-databinding", + "org.grails:grails-dependencies", + "org.grails:grails-docs", + "org.grails:grails-encoder", + "org.grails:grails-gradle-model", + "org.grails:grails-logging", + "org.grails:grails-plugin-codecs", + "org.grails:grails-plugin-controllers", + "org.grails:grails-plugin-databinding", + "org.grails:grails-plugin-datasource", + "org.grails:grails-plugin-domain-class", + "org.grails:grails-plugin-i18n", + "org.grails:grails-plugin-interceptors", + "org.grails:grails-plugin-mimetypes", + "org.grails:grails-plugin-rest", + "org.grails:grails-plugin-services", + "org.grails:grails-plugin-url-mappings", + "org.grails:grails-plugin-url-validation", + "org.grails:grails-shell", + "org.grails:grails-spring", + "org.grails:grails-test", + "org.grails:grails-validation", + "org.grails:grails-web", + "org.grails:grails-web-boot", + "org.grails:grails-web-common", + "org.grails:grails-web-databinding", + "org.grails:grails-web-fileupload", + "org.grails:grails-web-mvc", + "org.grails:grails-web-url-mappings" + ], + "groupName": "grails monorepo" + } + ] +} \ No newline at end of file diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml new file mode 100644 index 0000000..a01e1eb --- /dev/null +++ b/.github/workflows/gradle.yml @@ -0,0 +1,68 @@ +name: "Java CI" +on: + push: + branches: + - '[4-9]+.[0-9]+.x' + pull_request: + branches: + - '[4-9]+.[0-9]+.x' + workflow_dispatch: +jobs: + test_project: + name: "Test Project" + runs-on: ubuntu-24.04 + strategy: + fail-fast: true + matrix: + java: [17, 21] + steps: + - name: "📥 Checkout repository" + uses: actions/checkout@v4 + - name: "☕️ Setup JDK" + uses: actions/setup-java@v4 + with: + java-version: ${{ matrix.java }} + distribution: liberica + - name: "🐘 Setup Gradle" + uses: gradle/actions/setup-gradle@v4 + with: + develocity-access-key: ${{ secrets.DEVELOCITY_ACCESS_KEY }} + - name: "🏃 Run tests" + run: ./gradlew check + publish_snapshot: + if: github.event_name == 'push' || github.event_name == 'workflow_dispatch' + name: "Build Project and Publish Snapshot release" + needs: test_project + runs-on: ubuntu-24.04 + permissions: + contents: write # updates gh-pages branch + packages: write # publishes snapshot to GitHub Packages + steps: + - name: "📥 Checkout repository" + uses: actions/checkout@v4 + - name: "☕️ Setup JDK" + uses: actions/setup-java@v4 + with: + java-version: 17 + distribution: liberica + - name: "🐘 Setup Gradle" + uses: gradle/actions/setup-gradle@v4 + with: + develocity-access-key: ${{ secrets.DEVELOCITY_ACCESS_KEY }} + - name: "🔨 Build Project" + run: ./gradlew build + - name: "📤 Publish Snapshot version to Artifactory (repo.grails.org)" + env: + GRAILS_PUBLISH_RELEASE: 'false' + MAVEN_PUBLISH_USERNAME: ${{ secrets.MAVEN_PUBLISH_USERNAME }} + MAVEN_PUBLISH_PASSWORD: ${{ secrets.MAVEN_PUBLISH_PASSWORD }} + MAVEN_PUBLISH_URL: 'https://repo.grails.org/artifactory/plugins3-snapshots-local' + run: ./gradlew publish + - name: "📖 Generate Snapshot Documentation" + run: ./gradlew docs + - name: "📤 Publish Snapshot Documentation to Github Pages" + uses: apache/grails-github-actions/deploy-github-pages@asf + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GRADLE_PUBLISH_RELEASE: 'false' + SOURCE_FOLDER: build/docs \ No newline at end of file diff --git a/.github/workflows/release-notes.yml b/.github/workflows/release-notes.yml new file mode 100644 index 0000000..e41d6b4 --- /dev/null +++ b/.github/workflows/release-notes.yml @@ -0,0 +1,23 @@ +name: "Release Drafter" +on: + issues: + types: [closed, reopened] + push: + branches: + - master + - '[4-9]+.[0-9]+.x' + pull_request: + types: [opened, reopened, synchronize] + pull_request_target: + types: [opened, reopened, synchronize] +jobs: + update_release_draft: + permissions: + contents: write + pull-requests: write + runs-on: ubuntu-24.04 + steps: + - name: "📝 Update Release Draft" + uses: release-drafter/release-drafter@v6 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..ab000b1 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,130 @@ +name: Release +on: + release: + types: [ published ] +env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + JAVA_VERSION: '17.0.15' # this must be a specific version for reproducible builds + RELEASE_TAG_PREFIX: 'v' +jobs: + publish: + permissions: + packages: read # pre-release workflow + contents: write # to create release + issues: write # to modify milestones + runs-on: ubuntu-latest + outputs: + release_version: ${{ steps.release_version.outputs.value }} + extract_repository_name: ${{ steps.extract_repository_name.outputs.repository_name }} + steps: + - name: "📝 Store the current release version" + id: release_version + run: | + export RELEASE_VERSION="${{ github.ref_name }}" + export RELEASE_VERSION=${RELEASE_VERSION:${#RELEASE_TAG_PREFIX}} + echo "Found Release Version: ${RELEASE_VERSION}" + echo "value=${RELEASE_VERSION}" >> $GITHUB_OUTPUT + - name: "Extract repository name" + id: extract_repository_name + run: | + echo "repository_name=${GITHUB_REPOSITORY##*/}" >> $GITHUB_OUTPUT + - name: "📥 Checkout the repository" + uses: actions/checkout@v4 + with: + token: ${{ secrets.GITHUB_TOKEN }} + ref: v${{ steps.release_version.outputs.value }} + - name: 'Ensure Common Build Date' # to ensure a reproducible build + run: echo "SOURCE_DATE_EPOCH=$(git log -1 --pretty=%ct)" >> "$GITHUB_ENV" + - name: "Ensure source files use common date" + run: | + find . -depth \( -type f -o -type d \) -exec touch -d "@${SOURCE_DATE_EPOCH}" {} + + - name: "☕️ Setup JDK" + uses: actions/setup-java@v4 + with: + distribution: liberica + java-version: ${{ env.JAVA_VERSION }} + - name: "🐘 Setup Gradle" + uses: gradle/actions/setup-gradle@v4 + - name: "⚙️ Run pre-release" + uses: grails/github-actions/pre-release@asf + env: + RELEASE_VERSION: ${{ steps.release_version.outputs.value }} + - name: "🔐 Generate key file for artifact signing" + env: + SECRING_FILE: ${{ secrets.SECRING_FILE }} + run: | + printf "%s" "$SECRING_FILE" | base64 -d > "${{ github.workspace }}/secring.gpg" + - name: "🧩 Run Assemble" + id: assemble + run: | + ./gradlew -U assemble -Psigning.secretKeyRingFile=${{ github.workspace }}/secring.gpg -Psigning.keyId=${{ secrets.SIGNING_KEY }} + env: + GRAILS_PUBLISH_RELEASE: 'true' + SIGNING_KEY: ${{ secrets.SIGNING_KEY }} + SIGNING_PASSPHRASE: ${{ secrets.SIGNING_PASSPHRASE }} + - name: "📤 Publish to Maven Central" + env: + GRAILS_PUBLISH_RELEASE: 'true' + NEXUS_PUBLISH_USERNAME: ${{ secrets.NEXUS_PUBLISH_USERNAME }} + NEXUS_PUBLISH_PASSWORD: ${{ secrets.NEXUS_PUBLISH_PASSWORD }} + NEXUS_PUBLISH_URL: 'https://ossrh-staging-api.central.sonatype.com/service/local/' + NEXUS_PUBLISH_DESCRIPTION: '${{ steps.extract_repository_name.outputs.repository_name }}:${{ steps.release_version.outputs.value }}' + SIGNING_KEY: ${{ secrets.SIGNING_KEY }} + SIGNING_PASSPHRASE: ${{ secrets.SIGNING_PASSPHRASE }} + run: > + ./gradlew + -Psigning.keyId=${{ secrets.SIGNING_KEY }} + -Psigning.secretKeyRingFile=${{ github.workspace }}/secring.gpg + publishMavenPublicationToSonatypeRepository + closeSonatypeStagingRepository + - name: "Generate Build Date file" + run: echo "$SOURCE_DATE_EPOCH" >> build/BUILD_DATE.txt + - name: "Upload Build Date file" + uses: softprops/action-gh-release@da05d552573ad5aba039eaac05058a918a7bf631 + with: + files: build/BUILD_DATE.txt + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + release: + needs: publish + runs-on: ubuntu-latest + environment: release + permissions: + contents: write + issues: write + pull-requests: write + steps: + - name: "📥 Checkout repository" + uses: actions/checkout@v4 + with: + token: ${{ secrets.GITHUB_TOKEN }} + ref: v${{ needs.publish.outputs.release_version }} + - name: "☕️ Setup JDK" + uses: actions/setup-java@v4 + with: + distribution: liberica + java-version: ${{ env.JAVA_VERSION }} + - name: "🐘 Setup Gradle" + uses: gradle/actions/setup-gradle@v4 + - name: "📤 Release staging repository" + env: + GRAILS_PUBLISH_RELEASE: 'true' + NEXUS_PUBLISH_USERNAME: ${{ secrets.NEXUS_PUBLISH_USERNAME }} + NEXUS_PUBLISH_PASSWORD: ${{ secrets.NEXUS_PUBLISH_PASSWORD }} + NEXUS_PUBLISH_URL: 'https://ossrh-staging-api.central.sonatype.com/service/local/' + NEXUS_PUBLISH_DESCRIPTION: '${{ needs.publish.outputs.extract_repository_name }}:${{ needs.publish.outputs.release_version }}' + run: > + ./gradlew + findSonatypeStagingRepository + releaseSonatypeStagingRepository + - name: "📖 Generate Documentation" + run: ./gradlew docs + - name: "📤 Publish Documentation to Github Pages" + uses: apache/grails-github-actions/deploy-github-pages@asf + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GRADLE_PUBLISH_RELEASE: 'true' + SOURCE_FOLDER: build/docs + VERSION: ${{ needs.publish.outputs.release_version }} + - name: "⚙️ Run post-release" + uses: apache/grails-github-actions/post-release@asf diff --git a/.gitignore b/.gitignore index 74835a1..46eac81 100644 --- a/.gitignore +++ b/.gitignore @@ -1,12 +1,9 @@ build/ .gradle/ -target -plugin.xml -docs *.log *.zip .DS_Store -grails-rendering-* .settings .vscode/ bin/ +.idea diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index f1e4dcf..0000000 --- a/.travis.yml +++ /dev/null @@ -1,21 +0,0 @@ -sudo: false -cache: - directories: - - $HOME/.gradle -language: groovy -jdk: -- openjdk17 -before_script: -- rm -rf target -script: ./travis-build.sh -env: - global: - - GIT_NAME="Graeme Rocher" - - GIT_EMAIL="graeme.rocher@gmail.com" - - secure: qutwo7+0pfBh2fo2NrTdMdhK6Z7jGAGmfQUUms5IewycAEcO/XYD61uM9Om8y03puBXeo2aoN9YUtF5C+iou6KaGnLIMNDE6E5h9f36fTUk3RebwwV7cgsyzn4Zzma+EYYw6S2KF0Kj+JHPNDnlEdYLdmVJ1eq4KXVA17t5F8Eg= - - secure: G5bnlZc73YxAy9acnFuHpsEQ/JeKIawwT4pzv9S8ZIshVYdELWqBZiiDmiDiS1x4WhT1J9THWWy3/0Rp6taYA2IxNRgu4f9kPlv6m+Yb4pCl9E3zDfmdd1nnPeKpL7vrxawWQnF3PqqTX6qkY3PPiIdVUXdN1flUQOC0RoBXKBE= - - secure: IdiQoWkRWpDrWLNdROmGUgfdKGvccpozSXaicc3KV+Qe/ASyIKq54+oe196yvj5kTzkQqSkcHlt7icHuQfJBNjNCXhwP0TFoE55GoWzNmrJaxmr9jcvXOJzRicWp1ZrzksuoBiLxxyx2mfr3eSR7ByIyBN0aOY8n6Zcda5kE9wY= - - secure: Y9QjAlhmbRnE94ylUkg2dkOZh4u7aBgE9vol06dya/sjo8PpTtcMx1R5MNPPcPglvCiv0mmnNIu5QWPKWnWd+hp7wEI8NdLze8WL1iLaSIETtimrfuaMxRB8etFSsm9cs8B5SLbpNCqc0uCrA86Rts4hSQTrFIYJ416Ft/E8WSE= - - secure: o+BWtaPb6AldRYXHU15rBN/p/FIvEbar36LahiiXLKZ+2gTanBZAiDG6E/JuXRzVFqEMhOt8qvUXhpXXcxqHRvRVZqF0oqZJ8ratKwNB3W07ajEKMH8axK+Hxt/2P12Bk62ttDGxI/aFeH74RbQtNmFc+gLTS3O1QoLDLpqlVgk= - - secure: MBg9I3LeXHMhjhXkf+b8Gyy6afTUHfpsaK5IKXPJr9AycSx8r/CnFQTesdGFcrIhLfDYCmxL7YcA+/Fj9fOhu2bUo9rysG5pOlLmnU7DE56awIeMcdYB7ecty8mWJRSS4MJWsZ8I3kbncIVRORTvfgZfjh5WdmZaCKs11hX9x28= - - secure: SQc5o2xCxsuz8tlfBrxue7tDjanQ6NiI5/khYYc+7avECv+lH0W1b2Ho6G5ydk3eHQVxrrlF8LVrOeRlxg11UFcSmGoe6v3FO7KzvIXlZgHpq1CAR2Mojfp0YFXrAwvKetbGpiUOI+bMk5RCgUam8f1SWCkubwhQDXOO/T8I5a4= diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 587d235..5728e28 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -1,3 +1 @@ -* Luke Daley - Grails Plugin Collective -* Graeme Rocher - Grails Plugin Collective -* Randall Dietz - Software Projects +See https://github.com/gpc/rendering/graphs/contributors for contributors \ No newline at end of file diff --git a/build.gradle b/build.gradle index 823c6dc..741b4ff 100644 --- a/build.gradle +++ b/build.gradle @@ -1,3 +1,7 @@ +import java.time.Instant +import java.time.ZoneOffset +import java.time.format.DateTimeFormatter + buildscript { ext { grailsVersion = project.grailsVersion @@ -19,18 +23,23 @@ buildscript { } } -version "3.0.0-SNAPSHOT" +version = projectVersion group "org.grails.plugins" apply plugin: 'maven-publish' apply plugin:"org.apache.grails.gradle.grails-plugin" apply plugin:"org.apache.grails.gradle.grails-gsp" -// Used for publishing to central repository, remove if not needed -//apply from:'https://raw.githubusercontent.com/grails/grails-profile-repository/master/profiles/plugin/templates/grailsCentralPublishing.gradle' +apply plugin: 'org.apache.grails.gradle.grails-publish' +apply plugin: 'java-library' ext { - grailsVersion = project.grailsVersion - gradleWrapperVersion = project.gradleWrapperVersion + buildInstant = java.util.Optional.ofNullable(System.getenv("SOURCE_DATE_EPOCH")) + .filter(s -> !s.isEmpty()) + .map(Long::parseLong) + .map(Instant::ofEpochSecond) + .orElseGet(Instant::now) as Instant + formattedBuildDate = DateTimeFormatter.ISO_INSTANT.format(buildInstant) + buildDate = buildInstant.atZone(ZoneOffset.UTC) // for reproducible builds } repositories { @@ -49,15 +58,15 @@ dependencies { compileOnly platform("org.apache.grails:grails-bom:$grailsVersion") compileOnly 'org.apache.grails:grails-dependencies-starter-web' + api('org.xhtmlrenderer:flying-saucer-pdf-openpdf:9.4.0') + api("org.apache.pdfbox:pdfbox:3.0.5") + + testImplementation platform("org.apache.grails:grails-bom:$grailsVersion") testImplementation "org.apache.grails:grails-testing-support-datamapping" testImplementation "org.spockframework:spock-core" testImplementation "org.apache.grails:grails-testing-support-web" - implementation 'org.xhtmlrenderer:flying-saucer-pdf-openpdf:9.1.22' - testImplementation("org.apache.pdfbox:pdfbox:3.0.5") { - exclude module:'jempbox' - } } compileJava.options.release = 17 @@ -73,4 +82,36 @@ jar { tasks.withType(Test).configureEach { useJUnitPlatform() + testLogging { + events 'passed', 'skipped', 'failed', 'standardOut', 'standardError' + } +} + +groovydoc { + excludes = ['**/*GrailsPlugin.groovy', '**/Application.groovy'] } + +grailsPublish { + githubSlug = 'gpc/rendering' + license { + name = 'Apache-2.0' + } + title = 'Rendering Plugin' + desc = 'Render GSPs as PDFs, JPEGs, GIFs and PNGs' + developers = [ + ldaley : "Luke Daley", + graemerocher: "Graeme Rocher", + burtbeckwith: "Burt Beckwith", + sbglasius : "Søren Berg Glasius", + magx2 : "Martin", + Ari651 : "Ari Bustamante", + billgonemad : "William Malinowski", + ZacharyKlein: "Zachary Klein", + halfbaked : "Eamonn O'Connell", + codeconsole : "Scott Murphy", + ] +} + +compileJava.options.release = javaVersion.toInteger() + +apply from: layout.projectDirectory.file('gradle/docs-config.gradle') diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle new file mode 100644 index 0000000..766bcee --- /dev/null +++ b/buildSrc/build.gradle @@ -0,0 +1,26 @@ +plugins { + id 'groovy-gradle-plugin' +} + +file('../gradle.properties').withInputStream { + def gradleProperties = new Properties() + gradleProperties.load(it) + gradleProperties.each { k, v -> ext.set(k, v) } + +} + +repositories { + maven { url = 'https://repo.grails.org/grails/restricted' } + maven { + url = 'https://repository.apache.org/content/groups/snapshots' + content { + includeVersionByRegex('org[.]apache[.](grails|groovy).*', '.*', '.*-SNAPSHOT') + } + } +} + +dependencies { + implementation platform("org.apache.grails:grails-bom:$grailsVersion") + implementation "org.asciidoctor.jvm.convert:org.asciidoctor.jvm.convert.gradle.plugin:$asciidoctorGradlePluginVersion" + implementation 'org.apache.grails:grails-gradle-plugins' +} \ No newline at end of file diff --git a/example/.gitignore b/example/.gitignore new file mode 100644 index 0000000..dcdf017 --- /dev/null +++ b/example/.gitignore @@ -0,0 +1,45 @@ +### Gradle ### +.gradle +build/ +!gradle/wrapper/gradle-wrapper.jar +!**/src/main/**/build/ +!**/src/test/**/build/ +!**/src/integration-test/**/build/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache +bin/ +!**/src/main/**/bin/ +!**/src/test/**/bin/ +!**/src/integration-test/**/bin/ + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr +out/ +!**/src/main/**/out/ +!**/src/test/**/out/ +!**/src/integration-test/**/out/ + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ + +### VS Code ### +.vscode/ + +### Other ### +Thumbs.db +.DS_Store +target/ diff --git a/example/README.md b/example/README.md new file mode 100644 index 0000000..d7b8a8f --- /dev/null +++ b/example/README.md @@ -0,0 +1,25 @@ +## Grails 7.0.0-RC2 Documentation + +- [User Guide](https://docs.grails.org/7.0.0-RC2/guide/index.html) +- [API Reference](https://docs.grails.org/7.0.0-RC2/api/index.html) +- [Grails Guides](https://guides.grails.org/index.html) +--- + +## Feature scaffolding documentation + +- [Grails Scaffolding documentation](https://docs.grails.org/7.0.0-RC2/guide/scaffolding.html) + +## Feature asset-pipeline-grails documentation + +- [Grails Asset Pipeline documentation](https://github.com/wondrify/asset-pipeline#readme) + +## Feature spring-boot-devtools documentation + +- [Grails SpringBoot Developer Tools documentation](https://docs.spring.io/spring-boot/reference/using/devtools.html) + +## Feature geb-with-testcontainers documentation + +- [Grails Geb Functional Testing for Grails with Testcontainers documentation](https://github.com/apache/grails-geb#readme) + +- [https://groovy.apache.org/geb/manual/current/](https://groovy.apache.org/geb/manual/current/) + diff --git a/example/build.gradle b/example/build.gradle new file mode 100644 index 0000000..4facb35 --- /dev/null +++ b/example/build.gradle @@ -0,0 +1,96 @@ +buildscript { + repositories { + mavenCentral() + maven { + url = 'https://repo.grails.org/grails/restricted' + } + } + dependencies { // Not Published to Gradle Plugin Portal + classpath "cloud.wondrify:asset-pipeline-gradle" + classpath platform("org.apache.grails:grails-bom:$grailsVersion") + classpath "org.apache.grails:grails-data-hibernate5" + classpath "org.apache.grails:grails-gradle-plugins" + } +} + +plugins { + id "war" + id "idea" + id "eclipse" +} + +// Not Published to Gradle Plugin Portal +apply plugin: "org.apache.grails.gradle.grails-web" +apply plugin: "org.apache.grails.gradle.grails-gsp" +apply plugin: "cloud.wondrify.asset-pipeline" + +group = "example" + +repositories { + mavenCentral() + maven { + url = 'https://repo.grails.org/grails/restricted' + } +} + +dependencies { + profile "org.apache.grails.profiles:web" + developmentOnly "org.springframework.boot:spring-boot-devtools" // Spring Boot DevTools may cause performance slowdowns or compatibility issues on larger applications + testAndDevelopmentOnly "org.webjars.npm:bootstrap" + testAndDevelopmentOnly "org.webjars.npm:bootstrap-icons" + testAndDevelopmentOnly "org.webjars.npm:jquery" + implementation platform("org.apache.grails:grails-bom:$grailsVersion") + implementation "org.apache.grails:grails-core" + implementation "org.apache.grails:grails-data-hibernate5" + implementation "org.apache.grails:grails-databinding" + implementation "org.apache.grails:grails-events" + implementation "org.apache.grails:grails-gsp" + implementation "org.apache.grails:grails-interceptors" + implementation "org.apache.grails:grails-layout" + implementation "org.apache.grails:grails-logging" + implementation "org.apache.grails:grails-rest-transforms" + implementation "org.apache.grails:grails-scaffolding" + implementation "org.apache.grails:grails-services" + implementation "org.apache.grails:grails-url-mappings" + implementation "org.apache.grails:grails-web-boot" + implementation "org.springframework.boot:spring-boot-autoconfigure" + implementation "org.springframework.boot:spring-boot-starter" + implementation "org.springframework.boot:spring-boot-starter-actuator" + implementation "org.springframework.boot:spring-boot-starter-logging" + implementation "org.springframework.boot:spring-boot-starter-tomcat" + implementation "org.springframework.boot:spring-boot-starter-validation" + console "org.apache.grails:grails-console" + runtimeOnly "cloud.wondrify:asset-pipeline-grails" + runtimeOnly "com.h2database:h2" + runtimeOnly "com.zaxxer:HikariCP" + runtimeOnly "org.fusesource.jansi:jansi" + integrationTestImplementation testFixtures("org.apache.grails:grails-geb") + testImplementation "org.apache.grails:grails-testing-support-datamapping" + testImplementation "org.apache.grails:grails-testing-support-web" + testImplementation "org.spockframework:spock-core" + + implementation project(':') + +} + +compileJava.options.release = 17 + +tasks.withType(Test).configureEach { + useJUnitPlatform() +} + +assets { + excludes = [ + 'webjars/jquery/**', + 'webjars/bootstrap/**', + 'webjars/bootstrap-icons/**' + ] + includes = [ + 'webjars/jquery/*/dist/jquery.js', + 'webjars/bootstrap/*/dist/js/bootstrap.bundle.js', + 'webjars/bootstrap/*/dist/css/bootstrap.css', + 'webjars/bootstrap-icons/*/font/bootstrap-icons.css', + 'webjars/bootstrap-icons/*/font/fonts/*', + ] +} + diff --git a/example/gradle.properties b/example/gradle.properties new file mode 100644 index 0000000..6d7deba --- /dev/null +++ b/example/gradle.properties @@ -0,0 +1,6 @@ +grailsVersion=7.0.0-RC2 +version=0.1 +org.gradle.caching=true +org.gradle.daemon=true +org.gradle.parallel=true +org.gradle.jvmargs=-Dfile.encoding=UTF-8 -Xmx1024M diff --git a/example/gradle/wrapper/gradle-wrapper.jar b/example/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..1b33c55 Binary files /dev/null and b/example/gradle/wrapper/gradle-wrapper.jar differ diff --git a/example/gradle/wrapper/gradle-wrapper.properties b/example/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..d4081da --- /dev/null +++ b/example/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/example/gradlew b/example/gradlew new file mode 100755 index 0000000..23d15a9 --- /dev/null +++ b/example/gradlew @@ -0,0 +1,251 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH="\\\"\\\"" + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/example/gradlew.bat b/example/gradlew.bat new file mode 100644 index 0000000..db3a6ac --- /dev/null +++ b/example/gradlew.bat @@ -0,0 +1,94 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH= + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/web-app/fonts/arial.ttf b/example/grails-app/assets/fonts/arial.ttf similarity index 100% rename from web-app/fonts/arial.ttf rename to example/grails-app/assets/fonts/arial.ttf diff --git a/example/grails-app/assets/images/advancedgrails.svg b/example/grails-app/assets/images/advancedgrails.svg new file mode 100644 index 0000000..8b63ec8 --- /dev/null +++ b/example/grails-app/assets/images/advancedgrails.svg @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + diff --git a/example/grails-app/assets/images/apple-touch-icon-retina.png b/example/grails-app/assets/images/apple-touch-icon-retina.png new file mode 100644 index 0000000..d5bc4c0 Binary files /dev/null and b/example/grails-app/assets/images/apple-touch-icon-retina.png differ diff --git a/example/grails-app/assets/images/apple-touch-icon.png b/example/grails-app/assets/images/apple-touch-icon.png new file mode 100644 index 0000000..c3681cc Binary files /dev/null and b/example/grails-app/assets/images/apple-touch-icon.png differ diff --git a/example/grails-app/assets/images/documentation.svg b/example/grails-app/assets/images/documentation.svg new file mode 100644 index 0000000..29bc9d5 --- /dev/null +++ b/example/grails-app/assets/images/documentation.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + diff --git a/example/grails-app/assets/images/favicon.ico b/example/grails-app/assets/images/favicon.ico new file mode 100644 index 0000000..76e4b11 Binary files /dev/null and b/example/grails-app/assets/images/favicon.ico differ diff --git a/example/grails-app/assets/images/grails-cupsonly-logo-white.svg b/example/grails-app/assets/images/grails-cupsonly-logo-white.svg new file mode 100644 index 0000000..d3fe882 --- /dev/null +++ b/example/grails-app/assets/images/grails-cupsonly-logo-white.svg @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/example/grails-app/assets/images/grails.png b/example/grails-app/assets/images/grails.png new file mode 100644 index 0000000..93df8f9 Binary files /dev/null and b/example/grails-app/assets/images/grails.png differ diff --git a/example/grails-app/assets/images/grails.svg b/example/grails-app/assets/images/grails.svg new file mode 100644 index 0000000..79f698b --- /dev/null +++ b/example/grails-app/assets/images/grails.svg @@ -0,0 +1,13 @@ + + + + grails + Created with Sketch. + + + + + + + + \ No newline at end of file diff --git a/example/grails-app/assets/images/slack.svg b/example/grails-app/assets/images/slack.svg new file mode 100644 index 0000000..34fcf4c --- /dev/null +++ b/example/grails-app/assets/images/slack.svg @@ -0,0 +1,18 @@ + + + + slack_orange + Created with Sketch. + + + + + + + + + + + + + \ No newline at end of file diff --git a/example/grails-app/assets/javascripts/application.js b/example/grails-app/assets/javascripts/application.js new file mode 100644 index 0000000..c290381 --- /dev/null +++ b/example/grails-app/assets/javascripts/application.js @@ -0,0 +1,20 @@ +// This is a manifest file that'll be compiled into application.js. +// +// Any JavaScript file within this directory can be referenced here using a relative path. +// +// You're free to add application-wide JavaScript to this file, but it's generally better +// to create separate JavaScript files as needed. +// +//= require webjars/jquery/3.7.1/dist/jquery.js +//= require webjars/bootstrap/5.3.7/dist/js/bootstrap.bundle +//= require_self + +if (typeof jQuery !== 'undefined') { + (function($) { + $('#spinner').ajaxStart(function() { + $(this).fadeIn(); + }).ajaxStop(function() { + $(this).fadeOut(); + }); + })(jQuery); +} \ No newline at end of file diff --git a/example/grails-app/assets/stylesheets/application.css b/example/grails-app/assets/stylesheets/application.css new file mode 100644 index 0000000..ec60949 --- /dev/null +++ b/example/grails-app/assets/stylesheets/application.css @@ -0,0 +1,14 @@ +/* +* This is a manifest file that'll be compiled into application.css, which will include all the files +* listed below. +* +* Any CSS file within this directory can be referenced here using a relative path. +* +* You're free to add application-wide styles to this file and they'll appear at the top of the +* compiled file, but it's generally better to create a new file per style scope. +* +*= require webjars/bootstrap/5.3.7/dist/css/bootstrap +*= require webjars/bootstrap-icons/1.13.1/font/bootstrap-icons +*= require grails +*= require_self +*/ diff --git a/example/grails-app/assets/stylesheets/errors.css b/example/grails-app/assets/stylesheets/errors.css new file mode 100644 index 0000000..bd71149 --- /dev/null +++ b/example/grails-app/assets/stylesheets/errors.css @@ -0,0 +1,90 @@ +.filename { + font-style: italic; +} + +.exceptionMessage { + margin: 10px; + border: 1px solid #000; + padding: 5px; + background-color: #E9E9E9; +} + +.stack, +.snippet { + margin: 10px 0; +} + +.stack, +.snippet { + border: 1px solid #ccc; +} + +/* error details */ +.error-details { + border: 1px solid #FFAAAA; + background-color:#FFF3F3; + line-height: 1.5; + overflow: hidden; + padding: 10px 0 5px 25px; +} + +.error-details dt { + clear: left; + float: left; + font-weight: bold; + margin-right: 5px; +} + +.error-details dt:after { + content: ":"; +} + +.error-details dd { + display: block; +} + +/* stack trace */ +.stack { + padding: 5px; + overflow: auto; + height: 300px; +} + +/* code snippet */ +.snippet { + background-color: #fff; + font-family: monospace; +} + +.snippet .line { + display: block; +} + +.snippet .lineNumber { + background-color: #ddd; + color: #999; + display: inline-block; + margin-right: 5px; + padding: 0 3px; + text-align: right; + width: 3em; +} + +.snippet .error { + background-color: #fff3f3; + font-weight: bold; +} + +.snippet .error .lineNumber { + background-color: #faa; + color: #333; + font-weight: bold; +} + +.snippet .line:first-child .lineNumber { + padding-top: 5px; +} + +.snippet .line:last-child .lineNumber { + padding-bottom: 5px; +} \ No newline at end of file diff --git a/example/grails-app/assets/stylesheets/grails.css b/example/grails-app/assets/stylesheets/grails.css new file mode 100644 index 0000000..2ab6505 --- /dev/null +++ b/example/grails-app/assets/stylesheets/grails.css @@ -0,0 +1,77 @@ +table.scaffold tr>td:first-child, tr>th:first-child { + padding-left: 1.25em; +} + +table.scaffold tr>td:last-child, tr>th:last-child { + padding-right: 1.25em; +} + +table.scaffold th { + background-image: linear-gradient( + to bottom, + #ffffff 0%, + #f8f8f8 30%, + #eaeaea 70%, + #d4d4d4 100% + ); + border-bottom: 2px solid #b3b3b3; /* Adding a subtle shadow effect */ + box-shadow: 0 2px 3px rgba(0, 0, 0, 0.1); /* Adding a drop shadow */ +} + +[data-bs-theme=dark] table.scaffold th { + background-image: linear-gradient( + to bottom, + #4a4a4a 0%, + #3e3e3e 30%, + #2a2a2a 70%, + #1e1e1e 100% + ); + border-bottom: 2px solid #141414; /* Adding a subtle shadow effect */ + box-shadow: 0 2px 3px rgba(0, 0, 0, 0.3); /* Adding a drop shadow */ +} + +table.scaffold thead th { + white-space: nowrap; +} + +table.scaffold th a { + display: block; + text-decoration: none; +} + +table.scaffold th a:link, th a:visited { + color: #666666; +} + +table.scaffold th a:hover, th a:focus { + color: #333333; +} + +table.scaffold th.sortable a { + background-position: right; + background-repeat: no-repeat; + padding-right: 1.1em; +} + +table.scaffold th { + position: relative; +} + + +table.scaffold th.asc a:after { + content: '▲'; + position: absolute; + right: 10px; + font-size: 0.8em; +} + +table.scaffold th.desc a:after { + content: '▼'; + position: absolute; + right: 10px; + font-size: 0.8em; +} + +table.scaffold th:hover { + background: #f5f5f5 !important; +} \ No newline at end of file diff --git a/example/grails-app/conf/application.yml b/example/grails-app/conf/application.yml new file mode 100644 index 0000000..00e7eb3 --- /dev/null +++ b/example/grails-app/conf/application.yml @@ -0,0 +1,82 @@ +info: + app: + name: '@info.app.name@' + version: '@info.app.version@' + grailsVersion: '@info.app.grailsVersion@' +grails: + views: + default: + codec: html + gsp: + encoding: UTF-8 + htmlcodec: xml + codecs: + expression: html + scriptlet: html + taglib: none + staticparts: none + mime: + disable: + accept: + header: + userAgents: + - Gecko + - WebKit + - Presto + - Trident + types: + all: '*/*' + atom: application/atom+xml + css: text/css + csv: text/csv + form: application/x-www-form-urlencoded + html: + - text/html + - application/xhtml+xml + js: text/javascript + json: + - application/json + - text/json + multipartForm: multipart/form-data + pdf: application/pdf + rss: application/rss+xml + text: text/plain + hal: + - application/hal+json + - application/hal+xml + xml: + - text/xml + - application/xml + codegen: + defaultPackage: example + profile: web +dataSource: + driverClassName: org.h2.Driver + username: sa + password: '' + pooled: true + jmxExport: true +environments: + development: + dataSource: + dbCreate: create-drop + url: jdbc:h2:mem:devDb;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE + test: + dataSource: + dbCreate: update + url: jdbc:h2:mem:testDb;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE + production: + dataSource: + dbCreate: none + url: jdbc:h2:./prodDb;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE +hibernate: + cache: + queries: false + use_second_level_cache: false + use_query_cache: false +--- +server: + servlet: + context-path: /rendering +grails: + serverURL: http://localhost:8080/rendering \ No newline at end of file diff --git a/example/grails-app/conf/logback-spring.xml b/example/grails-app/conf/logback-spring.xml new file mode 100644 index 0000000..2f198ed --- /dev/null +++ b/example/grails-app/conf/logback-spring.xml @@ -0,0 +1,39 @@ + + + + + + true + + ${CONSOLE_LOG_THRESHOLD} + + + ${CONSOLE_LOG_PATTERN} + ${CONSOLE_LOG_CHARSET} + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/example/grails-app/conf/spring/resources.groovy b/example/grails-app/conf/spring/resources.groovy new file mode 100644 index 0000000..5008c27 --- /dev/null +++ b/example/grails-app/conf/spring/resources.groovy @@ -0,0 +1,3 @@ +// Place your Spring DSL code here +beans = { +} \ No newline at end of file diff --git a/grails-app/controllers/RenderingController.groovy b/example/grails-app/controllers/example/RenderingController.groovy similarity index 81% rename from grails-app/controllers/RenderingController.groovy rename to example/grails-app/controllers/example/RenderingController.groovy index 319cee4..ee06edc 100644 --- a/grails-app/controllers/RenderingController.groovy +++ b/example/grails-app/controllers/example/RenderingController.groovy @@ -1,3 +1,5 @@ +package example + /* * Copyright 2010 Grails Plugin Collective * @@ -13,38 +15,39 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -class RenderingController implements grails.plugins.rendering.RenderingTrait{ +class RenderingController { - def pdf = { + def index() {} + + def pdf() { renderPdf(template) } - def jpeg = { + def jpeg() { renderJpeg(template + [width: 200]) } - def gif = { + def gif() { renderGif(template + [render: [width: 600, height: 200], clip: [height: true, width: true], resize: [width: 600, height: 200]]) } - def png = { + def png() { renderPng(template + [width: 100]) } - def relative = { + def relative() { renderGif(template: 'relative') -/* render(template: 'relative')*/ } - def dataUriPdf = { + def dataUriPdf() { renderPdf(template: '/datauri') } - def dataUriImg = { + def dataUriImg() { renderGif(template: '/datauri') } - def encodingTest = { + def encodingTest() { renderPdf(template: "/encoding-test") } diff --git a/example/grails-app/controllers/example/UrlMappings.groovy b/example/grails-app/controllers/example/UrlMappings.groovy new file mode 100644 index 0000000..c2bc78b --- /dev/null +++ b/example/grails-app/controllers/example/UrlMappings.groovy @@ -0,0 +1,16 @@ +package example + +class UrlMappings { + static mappings = { + "/$controller/$action?/$id?(.$format)?"{ + constraints { + // apply constraints here + } + } + + "/"(view:"/index") + "500"(view:'/error') + "404"(view:'/notFound') + + } +} diff --git a/example/grails-app/i18n/messages.properties b/example/grails-app/i18n/messages.properties new file mode 100644 index 0000000..b045136 --- /dev/null +++ b/example/grails-app/i18n/messages.properties @@ -0,0 +1,56 @@ +default.doesnt.match.message=Property [{0}] of class [{1}] with value [{2}] does not match the required pattern [{3}] +default.invalid.url.message=Property [{0}] of class [{1}] with value [{2}] is not a valid URL +default.invalid.creditCard.message=Property [{0}] of class [{1}] with value [{2}] is not a valid credit card number +default.invalid.email.message=Property [{0}] of class [{1}] with value [{2}] is not a valid e-mail address +default.invalid.range.message=Property [{0}] of class [{1}] with value [{2}] does not fall within the valid range from [{3}] to [{4}] +default.invalid.size.message=Property [{0}] of class [{1}] with value [{2}] does not fall within the valid size range from [{3}] to [{4}] +default.invalid.max.message=Property [{0}] of class [{1}] with value [{2}] exceeds maximum value [{3}] +default.invalid.min.message=Property [{0}] of class [{1}] with value [{2}] is less than minimum value [{3}] +default.invalid.max.size.message=Property [{0}] of class [{1}] with value [{2}] exceeds the maximum size of [{3}] +default.invalid.min.size.message=Property [{0}] of class [{1}] with value [{2}] is less than the minimum size of [{3}] +default.invalid.validator.message=Property [{0}] of class [{1}] with value [{2}] does not pass custom validation +default.not.inlist.message=Property [{0}] of class [{1}] with value [{2}] is not contained within the list [{3}] +default.blank.message=Property [{0}] of class [{1}] cannot be blank +default.not.equal.message=Property [{0}] of class [{1}] with value [{2}] cannot equal [{3}] +default.null.message=Property [{0}] of class [{1}] cannot be null +default.not.unique.message=Property [{0}] of class [{1}] with value [{2}] must be unique + +default.paginate.prev=Previous +default.paginate.next=Next +default.boolean.true=True +default.boolean.false=False +default.date.format=yyyy-MM-dd HH:mm:ss z +default.number.format=0 + +default.created.message={0} {1} created +default.updated.message={0} {1} updated +default.deleted.message={0} {1} deleted +default.not.deleted.message={0} {1} could not be deleted +default.not.found.message={0} not found with id {1} +default.optimistic.locking.failure=Another user has updated this {0} while you were editing + +default.home.label=Home +default.list.label={0} List +default.add.label=Add {0} +default.new.label=New {0} +default.create.label=Create {0} +default.show.label=Show {0} +default.edit.label=Edit {0} + +default.button.create.label=Create +default.button.edit.label=Edit +default.button.update.label=Update +default.button.delete.label=Delete +default.button.delete.confirm.message=Are you sure? + +# Data binding errors. Use "typeMismatch.$className.$propertyName to customize (eg typeMismatch.Book.author) +typeMismatch.java.net.URL=Property {0} must be a valid URL +typeMismatch.java.net.URI=Property {0} must be a valid URI +typeMismatch.java.util.Date=Property {0} must be a valid Date +typeMismatch.java.lang.Double=Property {0} must be a valid number +typeMismatch.java.lang.Integer=Property {0} must be a valid number +typeMismatch.java.lang.Long=Property {0} must be a valid number +typeMismatch.java.lang.Short=Property {0} must be a valid number +typeMismatch.java.math.BigDecimal=Property {0} must be a valid number +typeMismatch.java.math.BigInteger=Property {0} must be a valid number +typeMismatch=Property {0} is type-mismatched diff --git a/example/grails-app/init/example/Application.groovy b/example/grails-app/init/example/Application.groovy new file mode 100644 index 0000000..1737c76 --- /dev/null +++ b/example/grails-app/init/example/Application.groovy @@ -0,0 +1,12 @@ +package example + +import grails.boot.GrailsApp +import grails.boot.config.GrailsAutoConfiguration +import groovy.transform.CompileStatic + +@CompileStatic +class Application extends GrailsAutoConfiguration { + static void main(String[] args) { + GrailsApp.run(Application, args) + } +} diff --git a/example/grails-app/init/example/BootStrap.groovy b/example/grails-app/init/example/BootStrap.groovy new file mode 100644 index 0000000..e9e593e --- /dev/null +++ b/example/grails-app/init/example/BootStrap.groovy @@ -0,0 +1,11 @@ +package example + +class BootStrap { + + def init = { + } + + def destroy = { + } + +} \ No newline at end of file diff --git a/grails-app/services/grails/plugins/rendering/test/BackgroundRenderingService.groovy b/example/grails-app/services/grails/plugins/rendering/test/BackgroundRenderingService.groovy similarity index 100% rename from grails-app/services/grails/plugins/rendering/test/BackgroundRenderingService.groovy rename to example/grails-app/services/grails/plugins/rendering/test/BackgroundRenderingService.groovy diff --git a/grails-app/views/_bad-xml.gsp b/example/grails-app/views/_bad-xml.gsp similarity index 100% rename from grails-app/views/_bad-xml.gsp rename to example/grails-app/views/_bad-xml.gsp diff --git a/grails-app/views/_datauri.gsp b/example/grails-app/views/_datauri.gsp similarity index 68% rename from grails-app/views/_datauri.gsp rename to example/grails-app/views/_datauri.gsp index 33d0892..ce35637 100644 --- a/grails-app/views/_datauri.gsp +++ b/example/grails-app/views/_datauri.gsp @@ -18,6 +18,8 @@

Below is an inline image

- Red dot +

It's a red dot.

+ Red dot \ No newline at end of file diff --git a/grails-app/views/_encoding-test.gsp b/example/grails-app/views/_encoding-test.gsp similarity index 94% rename from grails-app/views/_encoding-test.gsp rename to example/grails-app/views/_encoding-test.gsp index 6788dd1..9bab581 100644 --- a/grails-app/views/_encoding-test.gsp +++ b/example/grails-app/views/_encoding-test.gsp @@ -6,7 +6,7 @@ Osobowość - + \ No newline at end of file diff --git a/example/grails-app/views/rendering/index.gsp b/example/grails-app/views/rendering/index.gsp new file mode 100644 index 0000000..b9139cb --- /dev/null +++ b/example/grails-app/views/rendering/index.gsp @@ -0,0 +1,28 @@ +<%-- + Created by IntelliJ IDEA. + User: sbglasius + Date: 29/09/2025 + Time: 22.17 +--%> + +<%@ page contentType="text/html;charset=UTF-8" %> + + + + Rendering + + + + + + + \ No newline at end of file diff --git a/example/grails-forge-cli.yml b/example/grails-forge-cli.yml new file mode 100644 index 0000000..f00dc1d --- /dev/null +++ b/example/grails-forge-cli.yml @@ -0,0 +1,8 @@ +applicationType: web +defaultPackage: example +testFramework: spock +sourceLanguage: groovy +buildTool: gradle +gormImpl: gorm-hibernate5 +servletImpl: spring-boot-starter-tomcat +features: [app-name, asset-pipeline-grails, base, geb-with-testcontainers, gorm-hibernate5, gradle, grails-application, grails-console, grails-dependencies, grails-gorm-testing-support, grails-gradle-plugin, grails-gsp, grails-profiles, grails-url-mappings, grails-web, grails-web-testing-support, grails-wrapper, h2, logback, readme, scaffolding, spock, spring-boot-autoconfigure, spring-boot-devtools, spring-boot-starter, spring-boot-starter-tomcat, spring-resources, yaml] diff --git a/example/grails-wrapper.jar b/example/grails-wrapper.jar new file mode 100644 index 0000000..0498baa Binary files /dev/null and b/example/grails-wrapper.jar differ diff --git a/example/grailsw b/example/grailsw new file mode 100755 index 0000000..c27e487 --- /dev/null +++ b/example/grailsw @@ -0,0 +1,250 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 +# + +############################################################################## +# +# grailsw start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh grailsw +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRAILSW_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/grails-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRAILSW_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRAILSW_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + -classpath "$CLASSPATH" \ + grails.init.Start \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRAILSW_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/example/grailsw.bat b/example/grailsw.bat new file mode 100644 index 0000000..810aba1 --- /dev/null +++ b/example/grailsw.bat @@ -0,0 +1,94 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem grailsw startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRAILSW_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\grails-wrapper.jar + + +@rem Execute grailsw +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRAILSW_OPTS% -classpath "%CLASSPATH%" grails.init.Start %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRAILSW_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRAILSW_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/example/src/integration-test/groovy/example/ExampleSpec.groovy b/example/src/integration-test/groovy/example/ExampleSpec.groovy new file mode 100644 index 0000000..ae1c8d9 --- /dev/null +++ b/example/src/integration-test/groovy/example/ExampleSpec.groovy @@ -0,0 +1,19 @@ +package example +import grails.plugin.geb.ContainerGebSpec +import grails.testing.mixin.integration.Integration + +/** + * See https://docs.grails.org/latest/guide/testing.html#functionalTesting and https://groovy.apache.org/geb/manual/current/ + * for more instructions on how to write functional tests with Grails and Geb. + */ +@Integration +class ExampleSpec extends ContainerGebSpec { + + void 'should display the correct title on the home page'() { + when: 'visiting the home page' + go('/rendering') + + then: 'the page title is correct' + title == 'Welcome to Grails' + } +} diff --git a/src/integration-test/groovy/grails/plugins/rendering/BackgroundRenderingSpec.groovy b/example/src/integration-test/groovy/grails/plugins/rendering/BackgroundRenderingSpec.groovy similarity index 100% rename from src/integration-test/groovy/grails/plugins/rendering/BackgroundRenderingSpec.groovy rename to example/src/integration-test/groovy/grails/plugins/rendering/BackgroundRenderingSpec.groovy diff --git a/example/src/integration-test/groovy/grails/plugins/rendering/ControllerRelativeTemplateSpec.groovy b/example/src/integration-test/groovy/grails/plugins/rendering/ControllerRelativeTemplateSpec.groovy new file mode 100644 index 0000000..20a0cab --- /dev/null +++ b/example/src/integration-test/groovy/grails/plugins/rendering/ControllerRelativeTemplateSpec.groovy @@ -0,0 +1,57 @@ +/* + * Copyright 2010 Grails Plugin Collective + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package grails.plugins.rendering + +import grails.testing.mixin.integration.Integration +import org.springframework.beans.factory.annotation.Value +import org.springframework.http.HttpMethod +import org.springframework.web.client.RestTemplate +import spock.lang.Specification + +@Integration +class ControllerRelativeTemplateSpec extends Specification { + + @Value('${local.server.port}') + Integer port + RestTemplate restTemplate = new RestTemplate() + + def 'accessing controllers that does rendering'() { + when: + def resp = restTemplate.exchange( + getUrl(uri), + HttpMethod.GET, + null, + byte[].class + ) + then: + resp.statusCode.value() == 200 + resp.headers['Content-Type'] == [expectedContentType] + where: + uri | expectedContentType + 'gif' | 'image/gif' + 'jpeg' | 'image/jpeg' + 'png' | 'image/png' + 'pdf' | 'application/pdf' + 'dataUriImg' | 'image/gif' + 'dataUriPdf' | 'application/pdf' + 'relative' | 'image/gif' + 'encodingTest' | 'application/pdf' + } + + private String getUrl(String uri) { + return "http://localhost:${port}/rendering/rendering/${uri}" + } +} diff --git a/src/integration-test/groovy/grails/plugins/rendering/RenderingServiceSpec.groovy b/example/src/integration-test/groovy/grails/plugins/rendering/RenderingServiceSpec.groovy similarity index 100% rename from src/integration-test/groovy/grails/plugins/rendering/RenderingServiceSpec.groovy rename to example/src/integration-test/groovy/grails/plugins/rendering/RenderingServiceSpec.groovy diff --git a/src/integration-test/groovy/grails/plugins/rendering/document/XhtmlDocumentServiceSpec.groovy b/example/src/integration-test/groovy/grails/plugins/rendering/document/XhtmlDocumentServiceSpec.groovy similarity index 100% rename from src/integration-test/groovy/grails/plugins/rendering/document/XhtmlDocumentServiceSpec.groovy rename to example/src/integration-test/groovy/grails/plugins/rendering/document/XhtmlDocumentServiceSpec.groovy diff --git a/src/integration-test/groovy/grails/plugins/rendering/image/GifRenderingServiceSpec.groovy b/example/src/integration-test/groovy/grails/plugins/rendering/image/GifRenderingServiceSpec.groovy similarity index 100% rename from src/integration-test/groovy/grails/plugins/rendering/image/GifRenderingServiceSpec.groovy rename to example/src/integration-test/groovy/grails/plugins/rendering/image/GifRenderingServiceSpec.groovy diff --git a/src/integration-test/groovy/grails/plugins/rendering/image/ImageRenderingServiceSpec.groovy b/example/src/integration-test/groovy/grails/plugins/rendering/image/ImageRenderingServiceSpec.groovy similarity index 100% rename from src/integration-test/groovy/grails/plugins/rendering/image/ImageRenderingServiceSpec.groovy rename to example/src/integration-test/groovy/grails/plugins/rendering/image/ImageRenderingServiceSpec.groovy diff --git a/src/integration-test/groovy/grails/plugins/rendering/image/JpegRenderingServiceSpec.groovy b/example/src/integration-test/groovy/grails/plugins/rendering/image/JpegRenderingServiceSpec.groovy similarity index 100% rename from src/integration-test/groovy/grails/plugins/rendering/image/JpegRenderingServiceSpec.groovy rename to example/src/integration-test/groovy/grails/plugins/rendering/image/JpegRenderingServiceSpec.groovy diff --git a/src/integration-test/groovy/grails/plugins/rendering/image/PngRenderingServiceSpec.groovy b/example/src/integration-test/groovy/grails/plugins/rendering/image/PngRenderingServiceSpec.groovy similarity index 100% rename from src/integration-test/groovy/grails/plugins/rendering/image/PngRenderingServiceSpec.groovy rename to example/src/integration-test/groovy/grails/plugins/rendering/image/PngRenderingServiceSpec.groovy diff --git a/src/integration-test/groovy/grails/plugins/rendering/pdf/PdfRenderingServiceSpec.groovy b/example/src/integration-test/groovy/grails/plugins/rendering/pdf/PdfRenderingServiceSpec.groovy similarity index 97% rename from src/integration-test/groovy/grails/plugins/rendering/pdf/PdfRenderingServiceSpec.groovy rename to example/src/integration-test/groovy/grails/plugins/rendering/pdf/PdfRenderingServiceSpec.groovy index 2444710..d1f4300 100644 --- a/src/integration-test/groovy/grails/plugins/rendering/pdf/PdfRenderingServiceSpec.groovy +++ b/example/src/integration-test/groovy/grails/plugins/rendering/pdf/PdfRenderingServiceSpec.groovy @@ -19,7 +19,7 @@ import grails.plugins.rendering.RenderingServiceSpec import org.apache.pdfbox.pdfparser.PDFParser import org.apache.pdfbox.pdmodel.PDDocument -import org.apache.pdfbox.util.PDFTextStripper +import org.apache.pdfbox.text.PDFTextStripper class PdfRenderingServiceSpec extends RenderingServiceSpec { diff --git a/example/src/main/groovy/.gitkeep b/example/src/main/groovy/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/example/src/test/groovy/.gitkeep b/example/src/test/groovy/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/gradle.properties b/gradle.properties index 1d10095..dbbf8d1 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,2 +1,5 @@ +projectVersion=7.0.0-SNAPSHOT grailsVersion=7.0.0-RC2 -gradleWrapperVersion=8.14.3 +javaVersion=17 +asciidoctorGradlePluginVersion=4.0.4 + diff --git a/gradle/docs-config.gradle b/gradle/docs-config.gradle new file mode 100644 index 0000000..7088073 --- /dev/null +++ b/gradle/docs-config.gradle @@ -0,0 +1,67 @@ +import org.asciidoctor.gradle.jvm.AsciidoctorTask + +apply plugin: 'org.asciidoctor.jvm.convert' + +tasks.withType(Groovydoc).configureEach { + access = GroovydocAccess.PROTECTED + processScripts = false + includeMainForScripts = false + includeAuthor = false + destinationDir = layout.buildDirectory.dir('docs/api').get().asFile +} + +tasks.withType(AsciidoctorTask).configureEach { + baseDir = layout.projectDirectory.dir('src/main/asciidoc') + sourceDir = layout.projectDirectory.dir('src/main/asciidoc') + outputDir = layout.buildDirectory.dir('docs/manual') + sources { + include 'index.adoc' + } + jvm { + jvmArgs += [ + '--add-opens', 'java.base/sun.nio.ch=ALL-UNNAMED', + '--add-opens', 'java.base/java.io=ALL-UNNAMED' + ] + } + attributes = [ + copyright : 'Apache License, Version 2.0', + docinfo1 : 'true', + doctype : 'book', + encoding : 'utf-8', + icons : 'font', + id : "$rootProject.name:$version", + idprefix : '', + idseparator : '-', + lang : 'en', + linkattrs : true, + numbered : '', + producer : 'Asciidoctor', + revnumber : version, + setanchors : true, + 'source-highlighter' : 'prettify', + toc : 'left', + toc2 : '', + toclevels : '2', + projectVersion : version + ] +} + +tasks.register('docs') { + group = 'documentation' + def outputFile = layout.buildDirectory.file('docs/index.html') + inputs.files(tasks.named('asciidoctor'), tasks.named('groovydoc')) + outputs.file(outputFile) + doLast { + File redirectPage = outputFile.get().asFile + redirectPage.delete() + redirectPage.text = ''' + + + Redirecting... + + + + + '''.stripIndent(8) + } +} \ No newline at end of file diff --git a/grails-app/init/grails/plugins/rendering/Application.groovy b/grails-app/init/grails/plugins/rendering/Application.groovy index 311a082..8e55c76 100644 --- a/grails-app/init/grails/plugins/rendering/Application.groovy +++ b/grails-app/init/grails/plugins/rendering/Application.groovy @@ -2,7 +2,9 @@ package grails.plugins.rendering import grails.boot.GrailsApp import grails.boot.config.GrailsAutoConfiguration +import grails.plugins.metadata.PluginSource +@PluginSource class Application extends GrailsAutoConfiguration { static void main(String[] args) { GrailsApp.run(Application, args) diff --git a/grails-app/services/grails/plugins/rendering/RenderingService.groovy b/grails-app/services/grails/plugins/rendering/RenderingService.groovy index f3d324c..9b8eaf8 100644 --- a/grails-app/services/grails/plugins/rendering/RenderingService.groovy +++ b/grails-app/services/grails/plugins/rendering/RenderingService.groovy @@ -15,25 +15,28 @@ */ package grails.plugins.rendering +import grails.core.GrailsApplication +import grails.plugins.rendering.document.XhtmlDocumentService import grails.util.GrailsUtil - +import groovy.transform.CompileStatic import jakarta.servlet.http.HttpServletResponse import org.w3c.dom.Document +@CompileStatic abstract class RenderingService { static transactional = false - def xhtmlDocumentService - def grailsApplication + XhtmlDocumentService xhtmlDocumentService + GrailsApplication grailsApplication protected abstract doRender(Map args, Document document, OutputStream outputStream) - protected abstract getDefaultContentType() + protected abstract String getDefaultContentType() OutputStream render(Map args, OutputStream outputStream = new ByteArrayOutputStream()) { - def document = args.document ?: xhtmlDocumentService.createDocument(args) + Document document = args.document as Document ?: xhtmlDocumentService.createDocument(args) render(args, document, outputStream) } @@ -54,15 +57,15 @@ abstract class RenderingService { boolean render(Map args, HttpServletResponse response) { processArgs(args) if (args.bytes) { - writeToResponse(args, response, args.bytes) + writeToResponse(args, response, args.bytes as byte[]) } else if (args.input) { - writeToResponse(args, response, args.input) + writeToResponse(args, response, args.input as InputStream) } else { if (args.stream) { configureResponse(args, response) render(args, response.outputStream) } else { - writeToResponse(args, response, render(args).toByteArray()) + writeToResponse(args, response, (render(args) as ByteArrayOutputStream).toByteArray()) } } false @@ -70,8 +73,8 @@ abstract class RenderingService { protected writeToResponse(Map args, HttpServletResponse response, InputStream input) { configureResponse(args, response) - if (args.contentLength > 0) { - response.setContentLength(args.contentLength) + if ((args.contentLength as int) > 0) { + response.setContentLength(args.contentLength as int) } response.outputStream << input } @@ -92,7 +95,7 @@ abstract class RenderingService { } protected setContentType(Map args, HttpServletResponse response) { - response.setContentType(args.contentType ?: getDefaultContentType()) + response.setContentType(args.contentType as String ?: getDefaultContentType()) } protected setContentDisposition(Map args, HttpServletResponse response) { @@ -103,7 +106,7 @@ abstract class RenderingService { protected processArgs(Map args) { if (!args.base) { - args.base = grailsApplication.config.grails.serverURL ?: null + args.base = grailsApplication.config.get('grails.serverURL') ?: null } } } diff --git a/grails-app/services/grails/plugins/rendering/document/XhtmlDocumentService.groovy b/grails-app/services/grails/plugins/rendering/document/XhtmlDocumentService.groovy index b5922bc..f1f52ee 100644 --- a/grails-app/services/grails/plugins/rendering/document/XhtmlDocumentService.groovy +++ b/grails-app/services/grails/plugins/rendering/document/XhtmlDocumentService.groovy @@ -15,107 +15,111 @@ */ package grails.plugins.rendering.document +import grails.core.GrailsApplication import grails.util.GrailsUtil - - +import grails.util.Holders +import groovy.text.Template +import groovy.transform.CompileStatic +import org.grails.gsp.GroovyPagesTemplateEngine +import org.grails.web.pages.GroovyPagesUriSupport import org.w3c.dom.Document import org.xhtmlrenderer.resource.XMLResource import org.xml.sax.InputSource -import grails.util.Holders +@CompileStatic class XhtmlDocumentService { - static transactional = false - - def groovyPagesTemplateEngine - def groovyPagesUriService - def grailsApplication - - Document createDocument(Map args) { - createDocument(generateXhtml(args)) - } - - protected createDocument(String xhtml) { - try { - createDocument(new InputSource(new StringReader(xhtml))) - } catch (XmlParseException e) { - if (log.errorEnabled) { - GrailsUtil.deepSanitize(e) - log.error("caught xml parse exception for xhtml: $xhtml", e) - } - throw new XmlParseException(xhtml, e) - } - } - - protected createDocument(InputSource xhtml) { - try { - XMLResource.load(xhtml).document - } catch (Exception e) { - if (log.errorEnabled) { - GrailsUtil.deepSanitize(e) - log.error("xml parse exception for input source: $xhtml", e) - } - throw new XmlParseException(xhtml, e) - } - } - - protected generateXhtml(Map args) { - def xhtmlWriter = new StringWriter() - - RenderEnvironment.with(grailsApplication.mainContext, xhtmlWriter) { - createTemplate(args).make(args.model).writeTo(xhtmlWriter) - } - - def xhtml = xhtmlWriter.toString() - xhtmlWriter.close() - - if (log.debugEnabled) { - log.debug("xhtml for $args -- \n ${xhtml}") - } - - xhtml - } - - protected createTemplate(Map args) { - if (!args.template) { - throw new IllegalArgumentException("The 'template' argument must be specified") - } - def templateName = args.template - - if (templateName.startsWith("/")) { - if (!args.controller) { - args.controller = "" - } - } else { - if (!args.controller) { - throw new IllegalArgumentException("template names must start with '/' if controller is not provided") - } - } - - def contextPath = getContextPath(args) - def controllerName = args.controller instanceof CharSequence ? args.controller : groovyPagesUriService.getLogicalControllerName(args.controller) - def templateUri = groovyPagesUriService.getTemplateURI(controllerName, templateName) - def uris = ["$contextPath/$templateUri", "$contextPath/grails-app/views/$templateUri"] as String[] - def template = groovyPagesTemplateEngine.createTemplateForUri(uris) - - if (!template) { - throw new UnknownTemplateException(args.template, args.plugin) - } - - template - } - - protected getContextPath(args) { - def contextPath = args.contextPath?.toString() ?: "" - def pluginName = args.plugin - - if (pluginName) { - def plugin = Holders.pluginManager.getGrailsPlugin(pluginName) - if (plugin && !plugin.isBasePlugin()) { - contextPath = plugin.pluginPath - } - } - - contextPath - } + static transactional = false + + GroovyPagesTemplateEngine groovyPagesTemplateEngine + GroovyPagesUriSupport groovyPagesUriService + GrailsApplication grailsApplication + + Document createDocument(Map args) { + createDocument(generateXhtml(args)) + } + + protected Document createDocument(String xhtml) { + try { + createDocument(new InputSource(new StringReader(xhtml))) + } catch (XmlParseException e) { + if (log.errorEnabled) { + GrailsUtil.deepSanitize(e) + log.error("caught xml parse exception for xhtml: $xhtml", e) + } + throw new XmlParseException(xhtml, e) + } + } + + protected Document createDocument(InputSource xhtml) { + try { + XMLResource.load(xhtml).document + } catch (Exception e) { + if (log.errorEnabled) { + GrailsUtil.deepSanitize(e) + log.error("xml parse exception for input source: $xhtml", e) + } + throw new XmlParseException(xhtml, e) + } + } + + protected String generateXhtml(Map args) { + StringWriter xhtmlWriter = new StringWriter() + + RenderEnvironment.with(grailsApplication.mainContext, xhtmlWriter) { + createTemplate(args).make(args.model as Map).writeTo(xhtmlWriter) + } + + def xhtml = xhtmlWriter.toString() + xhtmlWriter.close() + + if (log.debugEnabled) { + log.debug("xhtml for $args -- \n ${xhtml}") + } + + xhtml + } + + protected Template createTemplate(Map args) { + if (!args.template) { + throw new IllegalArgumentException("The 'template' argument must be specified") + } + String templateName = args.template as String + + if (templateName.startsWith("/")) { + if (!args.controller) { + args.controller = "" + } + } else { + if (!args.controller) { + throw new IllegalArgumentException("template names must start with '/' if controller is not provided") + } + } + + String contextPath = getContextPath(args) + String controllerName = args.controller instanceof CharSequence ? args.controller : groovyPagesUriService.getLogicalControllerName(args.controller as GroovyObject) + String templateUri = groovyPagesUriService.getTemplateURI(controllerName, templateName) + String[] uris = ["$contextPath/$templateUri", "$contextPath/grails-app/views/$templateUri"] as String[] + Template template = groovyPagesTemplateEngine.createTemplateForUri(uris) + + if (!template) { + throw new UnknownTemplateException(args.template as String, args.plugin as String) + } + + template + } + + protected String getContextPath(Map args) { + String contextPath = args.contextPath?.toString() ?: "" + String pluginName = args.plugin + + if (pluginName) { + def plugin = Holders.pluginManager.getGrailsPlugin(pluginName) + if (plugin && !plugin.isBasePlugin()) { + contextPath = plugin.pluginPath + } + } + + contextPath + } } diff --git a/grails-app/services/grails/plugins/rendering/image/GifRenderingService.groovy b/grails-app/services/grails/plugins/rendering/image/GifRenderingService.groovy index 29ac45b..9c339a5 100644 --- a/grails-app/services/grails/plugins/rendering/image/GifRenderingService.groovy +++ b/grails-app/services/grails/plugins/rendering/image/GifRenderingService.groovy @@ -15,13 +15,16 @@ */ package grails.plugins.rendering.image +import groovy.transform.CompileStatic + +@CompileStatic class GifRenderingService extends ImageRenderingService { - protected getImageType() { + protected String getImageType() { "gif" } - protected getDefaultContentType() { + protected String getDefaultContentType() { "image/gif" } } diff --git a/grails-app/services/grails/plugins/rendering/image/ImageRenderingService.groovy b/grails-app/services/grails/plugins/rendering/image/ImageRenderingService.groovy index 03cba5b..61648f2 100644 --- a/grails-app/services/grails/plugins/rendering/image/ImageRenderingService.groovy +++ b/grails-app/services/grails/plugins/rendering/image/ImageRenderingService.groovy @@ -15,154 +15,157 @@ */ package grails.plugins.rendering.image + import grails.plugins.rendering.RenderingService import grails.plugins.rendering.datauri.DataUriAwareNaiveUserAgent +import groovy.transform.CompileDynamic +import groovy.transform.CompileStatic +import org.w3c.dom.Document +import org.xhtmlrenderer.simple.Graphics2DRenderer -import java.awt.Dimension -import java.awt.RenderingHints +import javax.imageio.ImageIO +import java.awt.* import java.awt.geom.AffineTransform import java.awt.image.BufferedImage +import java.awt.image.RenderedImage -import javax.imageio.ImageIO - -import org.w3c.dom.Document -import org.xhtmlrenderer.simple.Graphics2DRenderer - +@CompileStatic abstract class ImageRenderingService extends RenderingService { - static transactional = false - - static DEFAULT_BUFFERED_IMAGE_TYPE = BufferedImage.TYPE_INT_ARGB - - protected abstract getImageType() - - protected configureRenderer(Graphics2DRenderer renderer) { - renderer.sharedContext.userAgentCallback = new DataUriAwareNaiveUserAgent() - } - - protected doRender(Map args, Document document, OutputStream outputStream) { - convert(args, createBufferedImage(args, document), outputStream) - } - - protected convert(Map args, BufferedImage image, OutputStream outputStream) { - def imageType = getImageType() - if (!ImageIO.write(image, imageType, outputStream)) { - throw new IllegalArgumentException("ImageIO.write() failed to find writer for type '$type'") - } - } - - protected getDefaultBufferedImageType() { - DEFAULT_BUFFERED_IMAGE_TYPE - } - - protected BufferedImage createBufferedImage(Map args, Document document) { - def bufferedImageType = args.bufferedImageType ?: getDefaultBufferedImageType() - - int renderWidth = args.render?.width?.toInteger() ?: 10 - Integer renderHeight = args.render?.height?.toInteger() - - boolean autosizeWidth = args.autosize?.width == null || args.autosize?.width == true - boolean autosizeHeight = args.autosize?.height == null || args.autosize?.height == true - - def renderer = new Graphics2DRenderer() - configureRenderer(renderer) - renderer.setDocument(document, args.base) - - int imageWidth = renderWidth - Integer imageHeight = renderHeight - boolean needsLayout = true - - if (!renderHeight || autosizeWidth || autosizeHeight) { - def tempRenderHeight = renderHeight ?: 10000 - def dim = new Dimension(renderWidth, tempRenderHeight) - - // do layout with temp buffer to calculate height - def tempImage = new BufferedImage(dim.width.intValue(), dim.height.intValue(), bufferedImageType) - def tempGraphics = tempImage.graphics - renderer.layout(tempGraphics, dim) - needsLayout = false - tempGraphics.dispose() - - if (autosizeWidth) { - imageWidth = renderer.minimumSize.width.intValue() - } - if (!renderHeight || autosizeHeight) { - imageHeight = renderer.minimumSize.height.intValue() - } - } - - def image = new BufferedImage(imageWidth, imageHeight, bufferedImageType) - def graphics = image.graphics - if (needsLayout) { - renderer.layout(graphics, new Dimension(imageWidth, imageHeight)) - } - renderer.render(graphics) - graphics.dispose() - - if (args.scale) { - scale(image, args.scale, bufferedImageType) - } else if (args.resize) { - resize(image, args.resize, bufferedImageType) - } else { - image - } - } - - protected scale(image, Map scaleArgs, bufferedImageType) { - Integer width = scaleArgs.width?.toInteger() - Integer height = scaleArgs.height?.toInteger() - - if (width && height) { - scale(image, width, height, bufferedImageType) - } else if (width && !height) { - scale(image, width, width, bufferedImageType) - } else if (!width && height) { - scale(image, height, height, bufferedImageType) - } else { - throw new IllegalStateException("Unhandled scale height/width combination") - } - } - - protected resize(image, Map resizeArgs, bufferedImageType) { - Integer width = resizeArgs.width?.toInteger() - Integer height = resizeArgs.height?.toInteger() - - if (width && height) { - resize(image, width, height, bufferedImageType) - } else if (width && !height) { - height = (image.height * (width / image.width)).toInteger() - resize(image, width, height, bufferedImageType) - } else if (!width && height) { - width = (image.width * (height / image.height)).toInteger() - resize(image, width, height, bufferedImageType) - } else { - throw new IllegalStateException("Unhandled resize height/width combination") - } - } - - protected resize(image, width, height, bufferedImageType) { - double widthScale = width / image.width - double heightScale = height / image.height - - doScaleTransform(image, width, height, widthScale, heightScale, bufferedImageType) - } - - protected scale(image, widthScale, heightScale, bufferedImageType) { - int width = image.width * widthScale - int height = image.height * heightScale - - doScaleTransform(image, width, height, widthScale, heightScale, bufferedImageType) - } - - protected doScaleTransform(image, width, height, widthScale, heightScale, bufferedImageType) { - def scaled = new BufferedImage(width, height, bufferedImageType) - - def graphics = scaled.createGraphics() - graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC) - def transform = AffineTransform.getScaleInstance(widthScale, heightScale) - graphics.drawRenderedImage(image, transform) - graphics.dispose() - - scaled - } + static int DEFAULT_BUFFERED_IMAGE_TYPE = BufferedImage.TYPE_INT_ARGB + + protected abstract String getImageType() + + protected void configureRenderer(Graphics2DRenderer renderer) { + renderer.sharedContext.userAgentCallback = new DataUriAwareNaiveUserAgent() + } + + protected doRender(Map args, Document document, OutputStream outputStream) { + convert(args, createBufferedImage(args, document), outputStream) + } + + protected convert(Map args, BufferedImage image, OutputStream outputStream) { + def imageType = getImageType() + if (!ImageIO.write(image, imageType, outputStream)) { + throw new IllegalArgumentException("ImageIO.write() failed to find writer for type '$imageType'") + } + } + + protected int getDefaultBufferedImageType() { + DEFAULT_BUFFERED_IMAGE_TYPE + } + + @CompileDynamic + protected BufferedImage createBufferedImage(Map args, Document document) { + def bufferedImageType = args.bufferedImageType as Integer ?: getDefaultBufferedImageType() + + int renderWidth = args.render?.width?.toInteger() ?: 10 + Integer renderHeight = args.render?.height?.toInteger() + + boolean autosizeWidth = args.autosize?.width == null || args.autosize?.width == true + boolean autosizeHeight = args.autosize?.height == null || args.autosize?.height == true + + def renderer = new Graphics2DRenderer() + configureRenderer(renderer) + renderer.setDocument(document, args.base as String) + + int imageWidth = renderWidth + Integer imageHeight = renderHeight + boolean needsLayout = true + + if (!renderHeight || autosizeWidth || autosizeHeight) { + def tempRenderHeight = renderHeight ?: 10000 + def dim = new Dimension(renderWidth, tempRenderHeight) + + // do layout with temp buffer to calculate height + def tempImage = new BufferedImage(dim.width.intValue(), dim.height.intValue(), bufferedImageType) + def tempGraphics = tempImage.createGraphics() + renderer.layout(tempGraphics, dim) + needsLayout = false + tempGraphics.dispose() + + if (autosizeWidth) { + imageWidth = renderer.minimumSize.width.intValue() + } + if (!renderHeight || autosizeHeight) { + imageHeight = renderer.minimumSize.height.intValue() + } + } + + def image = new BufferedImage(imageWidth, imageHeight, bufferedImageType) + def graphics = image.createGraphics() + if (needsLayout) { + renderer.layout(graphics, new Dimension(imageWidth, imageHeight)) + } + renderer.render(graphics) + graphics.dispose() + + if (args.scale) { + scale(image, args.scale as Map, bufferedImageType) + } else if (args.resize) { + resize(image, args.resize as Map, bufferedImageType) + } else { + image + } + } + + @CompileDynamic + protected BufferedImage scale(Image image, Map scaleArgs, bufferedImageType) { + Integer width = scaleArgs.width?.toInteger() + Integer height = scaleArgs.height?.toInteger() + + if (width && height) { + scale(image, width, height, bufferedImageType) + } else if (width && !height) { + scale(image, width, width, bufferedImageType) + } else if (!width && height) { + scale(image, height, height, bufferedImageType) + } else { + throw new IllegalStateException("Unhandled scale height/width combination") + } + } + + @CompileDynamic + protected BufferedImage resize(BufferedImage image, Map resizeArgs, int bufferedImageType) { + Integer width = resizeArgs.width?.toInteger() + Integer height = resizeArgs.height?.toInteger() + + if (width && height) { + resize(image, width, height, bufferedImageType) + } else if (width && !height) { + height = (image.height * (width / image.width)).toInteger() + resize(image, width, height, bufferedImageType) + } else if (!width && height) { + width = (image.width * (height / image.height)).toInteger() + resize(image, width, height, bufferedImageType) + } else { + throw new IllegalStateException("Unhandled resize height/width combination") + } + } + + protected BufferedImage resize(BufferedImage image, int width, int height, int bufferedImageType) { + double widthScale = width / image.width + double heightScale = height / image.height + + doScaleTransform(image, width, height, widthScale, heightScale, bufferedImageType) + } + + protected BufferedImage scale(BufferedImage image, double widthScale, double heightScale, int bufferedImageType) { + int width = (image.width * widthScale).toInteger() + int height = (image.height * heightScale).toInteger() + + doScaleTransform(image, width, height, widthScale, heightScale, bufferedImageType) + } + + protected BufferedImage doScaleTransform(BufferedImage image, int width, int height, double widthScale, double heightScale, int bufferedImageType) { + def scaled = new BufferedImage(width, height, bufferedImageType) + + def graphics = scaled.createGraphics() + graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC) + def transform = AffineTransform.getScaleInstance(widthScale, heightScale) + graphics.drawRenderedImage(image as RenderedImage, transform) + graphics.dispose() + + scaled + } } diff --git a/grails-app/services/grails/plugins/rendering/image/JpegRenderingService.groovy b/grails-app/services/grails/plugins/rendering/image/JpegRenderingService.groovy index 80693ef..c534b6c 100644 --- a/grails-app/services/grails/plugins/rendering/image/JpegRenderingService.groovy +++ b/grails-app/services/grails/plugins/rendering/image/JpegRenderingService.groovy @@ -15,19 +15,22 @@ */ package grails.plugins.rendering.image +import groovy.transform.CompileStatic + import java.awt.image.BufferedImage +@CompileStatic class JpegRenderingService extends ImageRenderingService { - protected getImageType() { + protected String getImageType() { "jpeg" } - protected getDefaultContentType() { + protected String getDefaultContentType() { "image/jpeg" } - protected getDefaultBufferedImageType() { + protected int getDefaultBufferedImageType() { BufferedImage.TYPE_INT_RGB } } diff --git a/grails-app/services/grails/plugins/rendering/image/PngRenderingService.groovy b/grails-app/services/grails/plugins/rendering/image/PngRenderingService.groovy index fd584be..fdb4e86 100644 --- a/grails-app/services/grails/plugins/rendering/image/PngRenderingService.groovy +++ b/grails-app/services/grails/plugins/rendering/image/PngRenderingService.groovy @@ -15,13 +15,16 @@ */ package grails.plugins.rendering.image +import groovy.transform.CompileStatic + +@CompileStatic class PngRenderingService extends ImageRenderingService { - protected getImageType() { + protected String getImageType() { "png" } - protected getDefaultContentType() { + protected String getDefaultContentType() { "image/png" } } diff --git a/grails-app/services/grails/plugins/rendering/pdf/PdfRenderingService.groovy b/grails-app/services/grails/plugins/rendering/pdf/PdfRenderingService.groovy index 16972fa..7dfcb72 100644 --- a/grails-app/services/grails/plugins/rendering/pdf/PdfRenderingService.groovy +++ b/grails-app/services/grails/plugins/rendering/pdf/PdfRenderingService.groovy @@ -16,38 +16,24 @@ package grails.plugins.rendering.pdf import grails.plugins.rendering.RenderingService -import grails.plugins.rendering.datauri.DataUriAwareITextUserAgent - -import org.springframework.util.ReflectionUtils +import groovy.transform.CompileStatic import org.w3c.dom.Document import org.xhtmlrenderer.pdf.ITextRenderer +@CompileStatic class PdfRenderingService extends RenderingService { - static transactional = false - - PdfRenderingService() { - ReflectionUtils.makeAccessible(ITextRenderer.getDeclaredField("_outputDevice")) - } - - protected doRender(Map args, Document document, OutputStream outputStream) { - def renderer = new ITextRenderer() - configureRenderer(renderer) - renderer.setDocument(document, args.base) - renderer.layout() - renderer.createPDF(outputStream) - } + static transactional = false - protected getDefaultContentType() { - "application/pdf" - } + protected doRender(Map args, Document document, OutputStream outputStream) { + def renderer = new ITextRenderer() + renderer.setDocument(document, args.base as String) + renderer.layout() + renderer.createPDF(outputStream) + } - protected configureRenderer(ITextRenderer renderer) { - def outputDevice = renderer.@_outputDevice - def userAgent = new DataUriAwareITextUserAgent(outputDevice) - def sharedContext = renderer.sharedContext + protected String getDefaultContentType() { + "application/pdf" + } - sharedContext.userAgentCallback = userAgent - userAgent.sharedContext = sharedContext - } } diff --git a/grails-app/views/error.gsp b/grails-app/views/error.gsp deleted file mode 100644 index cfc512a..0000000 --- a/grails-app/views/error.gsp +++ /dev/null @@ -1,54 +0,0 @@ - - - Grails Runtime Exception - - - - -

Grails Runtime Exception

-

Error Details

- -
- Error ${request.'javax.servlet.error.status_code'}: ${request.'javax.servlet.error.message'.encodeAsHTML()}
- Servlet: ${request.'javax.servlet.error.servlet_name'}
- URI: ${request.'javax.servlet.error.request_uri'}
- - Exception Message: ${exception.message?.encodeAsHTML()}
- Caused by: ${exception.cause?.message?.encodeAsHTML()}
- Class: ${exception.className}
- At Line: [${exception.lineNumber}]
- Code Snippet:
-
- - ${cs?.encodeAsHTML()}
-
-
-
-
- -

Stack Trace

-
-
${it.encodeAsHTML()}
-
-
- - \ No newline at end of file diff --git a/plugins/pdf-plugin-test/.classpath b/plugins/pdf-plugin-test/.classpath deleted file mode 100644 index ebd5145..0000000 --- a/plugins/pdf-plugin-test/.classpath +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - \ No newline at end of file diff --git a/plugins/pdf-plugin-test/.project b/plugins/pdf-plugin-test/.project deleted file mode 100644 index fbb2f05..0000000 --- a/plugins/pdf-plugin-test/.project +++ /dev/null @@ -1,19 +0,0 @@ - - - pdf-plugin-test - - - - - - org.eclipse.jdt.core.javabuilder - - - - - - com.springsource.sts.grails.core.nature - org.eclipse.jdt.groovy.core.groovyNature - org.eclipse.jdt.core.javanature - - diff --git a/plugins/pdf-plugin-test/.settings/org.codehaus.groovy.eclipse.preferences.prefs b/plugins/pdf-plugin-test/.settings/org.codehaus.groovy.eclipse.preferences.prefs deleted file mode 100644 index bf339c7..0000000 --- a/plugins/pdf-plugin-test/.settings/org.codehaus.groovy.eclipse.preferences.prefs +++ /dev/null @@ -1,3 +0,0 @@ -#Created by grails -eclipse.preferences.version=1 -groovy.dont.generate.class.files=true diff --git a/plugins/pdf-plugin-test/PdfPluginTestGrailsPlugin.groovy b/plugins/pdf-plugin-test/PdfPluginTestGrailsPlugin.groovy deleted file mode 100644 index a488d88..0000000 --- a/plugins/pdf-plugin-test/PdfPluginTestGrailsPlugin.groovy +++ /dev/null @@ -1,50 +0,0 @@ -class PdfPluginTestGrailsPlugin { - // the plugin version - def version = "0.1" - // the version or versions of Grails the plugin is designed for - def grailsVersion = "1.2.0 > *" - // the other plugins this plugin depends on - def dependsOn = [:] - // resources that are excluded from plugin packaging - def pluginExcludes = [ - "grails-app/views/error.gsp" - ] - - // TODO Fill in these fields - def author = "Your name" - def authorEmail = "" - def title = "Plugin summary/headline" - def description = '''\\ -Brief description of the plugin. -''' - - // URL to the plugin's documentation - def documentation = "http://grails.org/plugin/pdf-plugin-test" - - def doWithWebDescriptor = { xml -> - // TODO Implement additions to web.xml (optional), this event occurs before - } - - def doWithSpring = { - // TODO Implement runtime spring config (optional) - } - - def doWithDynamicMethods = { ctx -> - // TODO Implement registering dynamic methods to classes (optional) - } - - def doWithApplicationContext = { applicationContext -> - // TODO Implement post initialization spring config (optional) - } - - def onChange = { event -> - // TODO Implement code that is executed when any artefact that this plugin is - // watching is modified and reloaded. The event contains: event.source, - // event.application, event.manager, event.ctx, and event.plugin. - } - - def onConfigChange = { event -> - // TODO Implement code that is executed when the project configuration changes. - // The event is the same as for 'onChange'. - } -} diff --git a/plugins/pdf-plugin-test/application.properties b/plugins/pdf-plugin-test/application.properties deleted file mode 100644 index b17a930..0000000 --- a/plugins/pdf-plugin-test/application.properties +++ /dev/null @@ -1,6 +0,0 @@ -#Grails Metadata file -#Mon Mar 22 17:46:49 EST 2010 -app.grails.version=1.2.0 -app.name=pdf-plugin-test -plugins.hibernate=1.2.0 -plugins.tomcat=1.2.0 diff --git a/plugins/pdf-plugin-test/grails-app/conf/BuildConfig.groovy b/plugins/pdf-plugin-test/grails-app/conf/BuildConfig.groovy deleted file mode 100644 index 2d9d6b4..0000000 --- a/plugins/pdf-plugin-test/grails-app/conf/BuildConfig.groovy +++ /dev/null @@ -1,31 +0,0 @@ -grails.project.class.dir = "target/classes" -grails.project.test.class.dir = "target/test-classes" -grails.project.test.reports.dir = "target/test-reports" -//grails.project.war.file = "target/${appName}-${appVersion}.war" -grails.project.dependency.resolution = { - // inherit Grails' default dependencies - inherits( "global" ) { - // uncomment to disable ehcache - // excludes 'ehcache' - } - log "warn" // log level of Ivy resolver, either 'error', 'warn', 'info', 'debug' or 'verbose' - repositories { - grailsPlugins() - grailsHome() - - // uncomment the below to enable remote dependency resolution - // from public Maven repositories - //mavenLocal() - //mavenCentral() - //mavenRepo "http://snapshots.repository.codehaus.org" - //mavenRepo "http://repository.codehaus.org" - //mavenRepo "http://download.java.net/maven/2/" - //mavenRepo "http://repository.jboss.com/maven2/" - } - dependencies { - // specify dependencies here under either 'build', 'compile', 'runtime', 'test' or 'provided' scopes eg. - - // runtime 'mysql:mysql-connector-java:5.1.5' - } - -} \ No newline at end of file diff --git a/plugins/pdf-plugin-test/grails-app/conf/DataSource.groovy b/plugins/pdf-plugin-test/grails-app/conf/DataSource.groovy deleted file mode 100644 index 20bd881..0000000 --- a/plugins/pdf-plugin-test/grails-app/conf/DataSource.groovy +++ /dev/null @@ -1,32 +0,0 @@ -dataSource { - pooled = true - driverClassName = "org.hsqldb.jdbcDriver" - username = "sa" - password = "" -} -hibernate { - cache.use_second_level_cache=true - cache.use_query_cache=true - cache.provider_class='net.sf.ehcache.hibernate.EhCacheProvider' -} -// environment specific settings -environments { - development { - dataSource { - dbCreate = "create-drop" // one of 'create', 'create-drop','update' - url = "jdbc:hsqldb:mem:devDB" - } - } - test { - dataSource { - dbCreate = "update" - url = "jdbc:hsqldb:mem:testDb" - } - } - production { - dataSource { - dbCreate = "update" - url = "jdbc:hsqldb:file:prodDb;shutdown=true" - } - } -} \ No newline at end of file diff --git a/plugins/pdf-plugin-test/grails-app/conf/UrlMappings.groovy b/plugins/pdf-plugin-test/grails-app/conf/UrlMappings.groovy deleted file mode 100644 index 41daf57..0000000 --- a/plugins/pdf-plugin-test/grails-app/conf/UrlMappings.groovy +++ /dev/null @@ -1,11 +0,0 @@ -class UrlMappings { - static mappings = { - "/$controller/$action?/$id?"{ - constraints { - // apply constraints here - } - } - "/"(view:"/index") - "500"(view:'/error') - } -} diff --git a/plugins/pdf-plugin-test/grails-app/views/_plugin-pdf.gsp b/plugins/pdf-plugin-test/grails-app/views/_plugin-pdf.gsp deleted file mode 100644 index 7d279c8..0000000 --- a/plugins/pdf-plugin-test/grails-app/views/_plugin-pdf.gsp +++ /dev/null @@ -1,8 +0,0 @@ - - - - -

This is a PDF from a plugin!

-

${var}

- - \ No newline at end of file diff --git a/plugins/pdf-plugin-test/grails-app/views/error.gsp b/plugins/pdf-plugin-test/grails-app/views/error.gsp deleted file mode 100644 index cfc512a..0000000 --- a/plugins/pdf-plugin-test/grails-app/views/error.gsp +++ /dev/null @@ -1,54 +0,0 @@ - - - Grails Runtime Exception - - - - -

Grails Runtime Exception

-

Error Details

- -
- Error ${request.'javax.servlet.error.status_code'}: ${request.'javax.servlet.error.message'.encodeAsHTML()}
- Servlet: ${request.'javax.servlet.error.servlet_name'}
- URI: ${request.'javax.servlet.error.request_uri'}
- - Exception Message: ${exception.message?.encodeAsHTML()}
- Caused by: ${exception.cause?.message?.encodeAsHTML()}
- Class: ${exception.className}
- At Line: [${exception.lineNumber}]
- Code Snippet:
-
- - ${cs?.encodeAsHTML()}
-
-
-
-
- -

Stack Trace

-
-
${it.encodeAsHTML()}
-
-
- - \ No newline at end of file diff --git a/plugins/pdf-plugin-test/web-app/WEB-INF/applicationContext.xml b/plugins/pdf-plugin-test/web-app/WEB-INF/applicationContext.xml deleted file mode 100644 index 6f42796..0000000 --- a/plugins/pdf-plugin-test/web-app/WEB-INF/applicationContext.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - - - Grails application factory bean - - - - - - A bean that manages Grails plugins - - - - - - - - - - - - - - - - - - classpath*:**/grails-app/**/*.groovy - - - - - - utf-8 - - - \ No newline at end of file diff --git a/plugins/pdf-plugin-test/web-app/WEB-INF/sitemesh.xml b/plugins/pdf-plugin-test/web-app/WEB-INF/sitemesh.xml deleted file mode 100644 index a547b41..0000000 --- a/plugins/pdf-plugin-test/web-app/WEB-INF/sitemesh.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/plugins/pdf-plugin-test/web-app/WEB-INF/tld/c.tld b/plugins/pdf-plugin-test/web-app/WEB-INF/tld/c.tld deleted file mode 100644 index 22698c9..0000000 --- a/plugins/pdf-plugin-test/web-app/WEB-INF/tld/c.tld +++ /dev/null @@ -1,563 +0,0 @@ - - - - - JSTL 1.1 core library - JSTL core - 1.1 - c - http://java.sun.com/jsp/jstl/core - - - - Provides core validation features for JSTL tags. - - - org.apache.taglibs.standard.tlv.JstlCoreTLV - - - - - - Catches any Throwable that occurs in its body and optionally - exposes it. - - catch - org.apache.taglibs.standard.tag.common.core.CatchTag - JSP - - -Name of the exported scoped variable for the -exception thrown from a nested action. The type of the -scoped variable is the type of the exception thrown. - - var - false - false - - - - - - Simple conditional tag that establishes a context for - mutually exclusive conditional operations, marked by - <when> and <otherwise> - - choose - org.apache.taglibs.standard.tag.common.core.ChooseTag - JSP - - - - - Simple conditional tag, which evalutes its body if the - supplied condition is true and optionally exposes a Boolean - scripting variable representing the evaluation of this condition - - if - org.apache.taglibs.standard.tag.rt.core.IfTag - JSP - - -The test condition that determines whether or -not the body content should be processed. - - test - true - true - boolean - - - -Name of the exported scoped variable for the -resulting value of the test condition. The type -of the scoped variable is Boolean. - - var - false - false - - - -Scope for var. - - scope - false - false - - - - - - Retrieves an absolute or relative URL and exposes its contents - to either the page, a String in 'var', or a Reader in 'varReader'. - - import - org.apache.taglibs.standard.tag.rt.core.ImportTag - org.apache.taglibs.standard.tei.ImportTEI - JSP - - -The URL of the resource to import. - - url - true - true - - - -Name of the exported scoped variable for the -resource's content. The type of the scoped -variable is String. - - var - false - false - - - -Scope for var. - - scope - false - false - - - -Name of the exported scoped variable for the -resource's content. The type of the scoped -variable is Reader. - - varReader - false - false - - - -Name of the context when accessing a relative -URL resource that belongs to a foreign -context. - - context - false - true - - - -Character encoding of the content at the input -resource. - - charEncoding - false - true - - - - - - The basic iteration tag, accepting many different - collection types and supporting subsetting and other - functionality - - forEach - org.apache.taglibs.standard.tag.rt.core.ForEachTag - org.apache.taglibs.standard.tei.ForEachTEI - JSP - - -Collection of items to iterate over. - - items - false - true - java.lang.Object - - - -If items specified: -Iteration begins at the item located at the -specified index. First item of the collection has -index 0. -If items not specified: -Iteration begins with index set at the value -specified. - - begin - false - true - int - - - -If items specified: -Iteration ends at the item located at the -specified index (inclusive). -If items not specified: -Iteration ends when index reaches the value -specified. - - end - false - true - int - - - -Iteration will only process every step items of -the collection, starting with the first one. - - step - false - true - int - - - -Name of the exported scoped variable for the -current item of the iteration. This scoped -variable has nested visibility. Its type depends -on the object of the underlying collection. - - var - false - false - - - -Name of the exported scoped variable for the -status of the iteration. Object exported is of type -javax.servlet.jsp.jstl.core.LoopTagStatus. This scoped variable has nested -visibility. - - varStatus - false - false - - - - - - Iterates over tokens, separated by the supplied delimeters - - forTokens - org.apache.taglibs.standard.tag.rt.core.ForTokensTag - JSP - - -String of tokens to iterate over. - - items - true - true - java.lang.String - - - -The set of delimiters (the characters that -separate the tokens in the string). - - delims - true - true - java.lang.String - - - -Iteration begins at the token located at the -specified index. First token has index 0. - - begin - false - true - int - - - -Iteration ends at the token located at the -specified index (inclusive). - - end - false - true - int - - - -Iteration will only process every step tokens -of the string, starting with the first one. - - step - false - true - int - - - -Name of the exported scoped variable for the -current item of the iteration. This scoped -variable has nested visibility. - - var - false - false - - - -Name of the exported scoped variable for the -status of the iteration. Object exported is of -type -javax.servlet.jsp.jstl.core.LoopTag -Status. This scoped variable has nested -visibility. - - varStatus - false - false - - - - - - Like <%= ... >, but for expressions. - - out - org.apache.taglibs.standard.tag.rt.core.OutTag - JSP - - -Expression to be evaluated. - - value - true - true - - - -Default value if the resulting value is null. - - default - false - true - - - -Determines whether characters <,>,&,'," in the -resulting string should be converted to their -corresponding character entity codes. Default value is -true. - - escapeXml - false - true - - - - - - - Subtag of <choose> that follows <when> tags - and runs only if all of the prior conditions evaluated to - 'false' - - otherwise - org.apache.taglibs.standard.tag.common.core.OtherwiseTag - JSP - - - - - Adds a parameter to a containing 'import' tag's URL. - - param - org.apache.taglibs.standard.tag.rt.core.ParamTag - JSP - - -Name of the query string parameter. - - name - true - true - - - -Value of the parameter. - - value - false - true - - - - - - Redirects to a new URL. - - redirect - org.apache.taglibs.standard.tag.rt.core.RedirectTag - JSP - - -The URL of the resource to redirect to. - - url - false - true - - - -Name of the context when redirecting to a relative URL -resource that belongs to a foreign context. - - context - false - true - - - - - - Removes a scoped variable (from a particular scope, if specified). - - remove - org.apache.taglibs.standard.tag.common.core.RemoveTag - empty - - -Name of the scoped variable to be removed. - - var - true - false - - - -Scope for var. - - scope - false - false - - - - - - Sets the result of an expression evaluation in a 'scope' - - set - org.apache.taglibs.standard.tag.rt.core.SetTag - JSP - - -Name of the exported scoped variable to hold the value -specified in the action. The type of the scoped variable is -whatever type the value expression evaluates to. - - var - false - false - - - -Expression to be evaluated. - - value - false - true - - - -Target object whose property will be set. Must evaluate to -a JavaBeans object with setter property property, or to a -java.util.Map object. - - target - false - true - - - -Name of the property to be set in the target object. - - property - false - true - - - -Scope for var. - - scope - false - false - - - - - - Creates a URL with optional query parameters. - - url - org.apache.taglibs.standard.tag.rt.core.UrlTag - JSP - - -Name of the exported scoped variable for the -processed url. The type of the scoped variable is -String. - - var - false - false - - - -Scope for var. - - scope - false - false - - - -URL to be processed. - - value - false - true - - - -Name of the context when specifying a relative URL -resource that belongs to a foreign context. - - context - false - true - - - - - - Subtag of <choose> that includes its body if its - condition evalutes to 'true' - - when - org.apache.taglibs.standard.tag.rt.core.WhenTag - JSP - - -The test condition that determines whether or not the -body content should be processed. - - test - true - true - boolean - - - - diff --git a/plugins/pdf-plugin-test/web-app/WEB-INF/tld/fmt.tld b/plugins/pdf-plugin-test/web-app/WEB-INF/tld/fmt.tld deleted file mode 100644 index 3b9a54a..0000000 --- a/plugins/pdf-plugin-test/web-app/WEB-INF/tld/fmt.tld +++ /dev/null @@ -1,671 +0,0 @@ - - - - - JSTL 1.1 i18n-capable formatting library - JSTL fmt - 1.1 - fmt - http://java.sun.com/jsp/jstl/fmt - - - - Provides core validation features for JSTL tags. - - - org.apache.taglibs.standard.tlv.JstlFmtTLV - - - - - - Sets the request character encoding - - requestEncoding - org.apache.taglibs.standard.tag.rt.fmt.RequestEncodingTag - empty - - -Name of character encoding to be applied when -decoding request parameters. - - value - false - true - - - - - - Stores the given locale in the locale configuration variable - - setLocale - org.apache.taglibs.standard.tag.rt.fmt.SetLocaleTag - empty - - -A String value is interpreted as the -printable representation of a locale, which -must contain a two-letter (lower-case) -language code (as defined by ISO-639), -and may contain a two-letter (upper-case) -country code (as defined by ISO-3166). -Language and country codes must be -separated by hyphen (-) or underscore -(_). - - value - true - true - - - -Vendor- or browser-specific variant. -See the java.util.Locale javadocs for -more information on variants. - - variant - false - true - - - -Scope of the locale configuration variable. - - scope - false - false - - - - - - Specifies the time zone for any time formatting or parsing actions - nested in its body - - timeZone - org.apache.taglibs.standard.tag.rt.fmt.TimeZoneTag - JSP - - -The time zone. A String value is interpreted as -a time zone ID. This may be one of the time zone -IDs supported by the Java platform (such as -"America/Los_Angeles") or a custom time zone -ID (such as "GMT-8"). See -java.util.TimeZone for more information on -supported time zone formats. - - value - true - true - - - - - - Stores the given time zone in the time zone configuration variable - - setTimeZone - org.apache.taglibs.standard.tag.rt.fmt.SetTimeZoneTag - empty - - -The time zone. A String value is interpreted as -a time zone ID. This may be one of the time zone -IDs supported by the Java platform (such as -"America/Los_Angeles") or a custom time zone -ID (such as "GMT-8"). See java.util.TimeZone for -more information on supported time zone -formats. - - value - true - true - - - -Name of the exported scoped variable which -stores the time zone of type -java.util.TimeZone. - - var - false - false - - - -Scope of var or the time zone configuration -variable. - - scope - false - false - - - - - - Loads a resource bundle to be used by its tag body - - bundle - org.apache.taglibs.standard.tag.rt.fmt.BundleTag - JSP - - -Resource bundle base name. This is the bundle's -fully-qualified resource name, which has the same -form as a fully-qualified class name, that is, it uses -"." as the package component separator and does not -have any file type (such as ".class" or ".properties") -suffix. - - basename - true - true - - - -Prefix to be prepended to the value of the message -key of any nested <fmt:message> action. - - prefix - false - true - - - - - - Loads a resource bundle and stores it in the named scoped variable or - the bundle configuration variable - - setBundle - org.apache.taglibs.standard.tag.rt.fmt.SetBundleTag - empty - - -Resource bundle base name. This is the bundle's -fully-qualified resource name, which has the same -form as a fully-qualified class name, that is, it uses -"." as the package component separator and does not -have any file type (such as ".class" or ".properties") -suffix. - - basename - true - true - - - -Name of the exported scoped variable which stores -the i18n localization context of type -javax.servlet.jsp.jstl.fmt.LocalizationC -ontext. - - var - false - false - - - -Scope of var or the localization context -configuration variable. - - scope - false - false - - - - - - Maps key to localized message and performs parametric replacement - - message - org.apache.taglibs.standard.tag.rt.fmt.MessageTag - JSP - - -Message key to be looked up. - - key - false - true - - - -Localization context in whose resource -bundle the message key is looked up. - - bundle - false - true - - - -Name of the exported scoped variable -which stores the localized message. - - var - false - false - - - -Scope of var. - - scope - false - false - - - - - - Supplies an argument for parametric replacement to a containing - <message> tag - - param - org.apache.taglibs.standard.tag.rt.fmt.ParamTag - JSP - - -Argument used for parametric replacement. - - value - false - true - - - - - - Formats a numeric value as a number, currency, or percentage - - formatNumber - org.apache.taglibs.standard.tag.rt.fmt.FormatNumberTag - JSP - - -Numeric value to be formatted. - - value - false - true - - - -Specifies whether the value is to be -formatted as number, currency, or -percentage. - - type - false - true - - - -Custom formatting pattern. - - pattern - false - true - - - -ISO 4217 currency code. Applied only -when formatting currencies (i.e. if type is -equal to "currency"); ignored otherwise. - - currencyCode - false - true - - - -Currency symbol. Applied only when -formatting currencies (i.e. if type is equal -to "currency"); ignored otherwise. - - currencySymbol - false - true - - - -Specifies whether the formatted output -will contain any grouping separators. - - groupingUsed - false - true - - - -Maximum number of digits in the integer -portion of the formatted output. - - maxIntegerDigits - false - true - - - -Minimum number of digits in the integer -portion of the formatted output. - - minIntegerDigits - false - true - - - -Maximum number of digits in the -fractional portion of the formatted output. - - maxFractionDigits - false - true - - - -Minimum number of digits in the -fractional portion of the formatted output. - - minFractionDigits - false - true - - - -Name of the exported scoped variable -which stores the formatted result as a -String. - - var - false - false - - - -Scope of var. - - scope - false - false - - - - - - Parses the string representation of a number, currency, or percentage - - parseNumber - org.apache.taglibs.standard.tag.rt.fmt.ParseNumberTag - JSP - - -String to be parsed. - - value - false - true - - - -Specifies whether the string in the value -attribute should be parsed as a number, -currency, or percentage. - - type - false - true - - - -Custom formatting pattern that determines -how the string in the value attribute is to be -parsed. - - pattern - false - true - - - -Locale whose default formatting pattern (for -numbers, currencies, or percentages, -respectively) is to be used during the parse -operation, or to which the pattern specified -via the pattern attribute (if present) is -applied. - - parseLocale - false - true - - - -Specifies whether just the integer portion of -the given value should be parsed. - - integerOnly - false - true - - - -Name of the exported scoped variable which -stores the parsed result (of type -java.lang.Number). - - var - false - false - - - -Scope of var. - - scope - false - false - - - - - - Formats a date and/or time using the supplied styles and pattern - - formatDate - org.apache.taglibs.standard.tag.rt.fmt.FormatDateTag - empty - - -Date and/or time to be formatted. - - value - true - true - - - -Specifies whether the time, the date, or both -the time and date components of the given -date are to be formatted. - - type - false - true - - - -Predefined formatting style for dates. Follows -the semantics defined in class -java.text.DateFormat. Applied only -when formatting a date or both a date and -time (i.e. if type is missing or is equal to -"date" or "both"); ignored otherwise. - - dateStyle - false - true - - - -Predefined formatting style for times. Follows -the semantics defined in class -java.text.DateFormat. Applied only -when formatting a time or both a date and -time (i.e. if type is equal to "time" or "both"); -ignored otherwise. - - timeStyle - false - true - - - -Custom formatting style for dates and times. - - pattern - false - true - - - -Time zone in which to represent the formatted -time. - - timeZone - false - true - - - -Name of the exported scoped variable which -stores the formatted result as a String. - - var - false - false - - - -Scope of var. - - scope - false - false - - - - - - Parses the string representation of a date and/or time - - parseDate - org.apache.taglibs.standard.tag.rt.fmt.ParseDateTag - JSP - - -Date string to be parsed. - - value - false - true - - - -Specifies whether the date string in the -value attribute is supposed to contain a -time, a date, or both. - - type - false - true - - - -Predefined formatting style for days -which determines how the date -component of the date string is to be -parsed. Applied only when formatting a -date or both a date and time (i.e. if type -is missing or is equal to "date" or "both"); -ignored otherwise. - - dateStyle - false - true - - - -Predefined formatting styles for times -which determines how the time -component in the date string is to be -parsed. Applied only when formatting a -time or both a date and time (i.e. if type -is equal to "time" or "both"); ignored -otherwise. - - timeStyle - false - true - - - -Custom formatting pattern which -determines how the date string is to be -parsed. - - pattern - false - true - - - -Time zone in which to interpret any time -information in the date string. - - timeZone - false - true - - - -Locale whose predefined formatting styles -for dates and times are to be used during -the parse operation, or to which the -pattern specified via the pattern -attribute (if present) is applied. - - parseLocale - false - true - - - -Name of the exported scoped variable in -which the parsing result (of type -java.util.Date) is stored. - - var - false - false - - - -Scope of var. - - scope - false - false - - - - diff --git a/plugins/pdf-plugin-test/web-app/WEB-INF/tld/grails.tld b/plugins/pdf-plugin-test/web-app/WEB-INF/tld/grails.tld deleted file mode 100644 index 868ec1f..0000000 --- a/plugins/pdf-plugin-test/web-app/WEB-INF/tld/grails.tld +++ /dev/null @@ -1,551 +0,0 @@ - - - The Grails (Groovy on Rails) custom tag library - 0.2 - grails - http://grails.codehaus.org/tags - - - - link - org.codehaus.groovy.grails.web.taglib.jsp.JspLinkTag - JSP - - action - false - true - - - controller - false - true - - - id - false - true - - - url - false - true - - - params - false - true - - true - - - form - org.codehaus.groovy.grails.web.taglib.jsp.JspFormTag - JSP - - action - false - true - - - controller - false - true - - - id - false - true - - - url - false - true - - - method - true - true - - true - - - select - org.codehaus.groovy.grails.web.taglib.jsp.JspSelectTag - JSP - - name - true - true - - - value - false - true - - - optionKey - false - true - - - optionValue - false - true - - true - - - datePicker - org.codehaus.groovy.grails.web.taglib.jsp.JspDatePickerTag - empty - - name - true - true - - - value - false - true - - - precision - false - true - - false - - - currencySelect - org.codehaus.groovy.grails.web.taglib.jsp.JspCurrencySelectTag - empty - - name - true - true - - - value - false - true - - true - - - localeSelect - org.codehaus.groovy.grails.web.taglib.jsp.JspLocaleSelectTag - empty - - name - true - true - - - value - false - true - - true - - - timeZoneSelect - org.codehaus.groovy.grails.web.taglib.jsp.JspTimeZoneSelectTag - empty - - name - true - true - - - value - false - true - - true - - - checkBox - org.codehaus.groovy.grails.web.taglib.jsp.JspCheckboxTag - empty - - name - true - true - - - value - true - true - - true - - - hasErrors - org.codehaus.groovy.grails.web.taglib.jsp.JspHasErrorsTag - JSP - - model - false - true - - - bean - false - true - - - field - false - true - - false - - - eachError - org.codehaus.groovy.grails.web.taglib.jsp.JspEachErrorTag - JSP - - model - false - true - - - bean - false - true - - - field - false - true - - false - - - renderErrors - org.codehaus.groovy.grails.web.taglib.jsp.JspEachErrorTag - JSP - - model - false - true - - - bean - false - true - - - field - false - true - - - as - true - true - - false - - - message - org.codehaus.groovy.grails.web.taglib.jsp.JspMessageTag - JSP - - code - false - true - - - error - false - true - - - default - false - true - - false - - - remoteFunction - org.codehaus.groovy.grails.web.taglib.jsp.JspRemoteFunctionTag - empty - - before - false - true - - - after - false - true - - - action - false - true - - - controller - false - true - - - id - false - true - - - url - false - true - - - params - false - true - - - asynchronous - false - true - - - method - false - true - - - update - false - true - - - onSuccess - false - true - - - onFailure - false - true - - - onComplete - false - true - - - onLoading - false - true - - - onLoaded - false - true - - - onInteractive - false - true - - true - - - remoteLink - org.codehaus.groovy.grails.web.taglib.jsp.JspRemoteLinkTag - JSP - - before - false - true - - - after - false - true - - - action - false - true - - - controller - false - true - - - id - false - true - - - url - false - true - - - params - false - true - - - asynchronous - false - true - - - method - false - true - - - update - false - true - - - onSuccess - false - true - - - onFailure - false - true - - - onComplete - false - true - - - onLoading - false - true - - - onLoaded - false - true - - - onInteractive - false - true - - true - - - formRemote - org.codehaus.groovy.grails.web.taglib.jsp.JspFormRemoteTag - JSP - - before - false - true - - - after - false - true - - - action - false - true - - - controller - false - true - - - id - false - true - - - url - false - true - - - params - false - true - - - asynchronous - false - true - - - method - false - true - - - update - false - true - - - onSuccess - false - true - - - onFailure - false - true - - - onComplete - false - true - - - onLoading - false - true - - - onLoaded - false - true - - - onInteractive - false - true - - true - - - invokeTag - org.codehaus.groovy.grails.web.taglib.jsp.JspInvokeGrailsTagLibTag - JSP - - it - java.lang.Object - true - NESTED - - - tagName - true - true - - true - - - diff --git a/plugins/pdf-plugin-test/web-app/WEB-INF/tld/spring.tld b/plugins/pdf-plugin-test/web-app/WEB-INF/tld/spring.tld deleted file mode 100644 index 1bc7091..0000000 --- a/plugins/pdf-plugin-test/web-app/WEB-INF/tld/spring.tld +++ /dev/null @@ -1,311 +0,0 @@ - - - - - - 1.1.1 - - 1.2 - - 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. - - - - 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). - - - - htmlEscape - false - true - - - - 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). - - - - code - false - true - - - - arguments - false - true - - - - text - false - true - - - - var - false - true - - - - scope - false - true - - - - htmlEscape - false - true - - - - 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). - - - - code - false - true - - - - arguments - false - true - - - - text - false - true - - - - var - false - true - - - - scope - false - true - - - - htmlEscape - false - true - - - - 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). - - - - errors - org.springframework.validation.Errors - - - - name - true - true - - - - 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 - java.lang.String - - - - 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). - - - - status - org.springframework.web.servlet.support.BindStatus - - - - path - true - true - - - - ignoreNestedPath - false - true - - - - 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). - - - - value - true - true - - - - var - false - true - - - - scope - false - true - - - - htmlEscape - false - true - - - - - diff --git a/settings.gradle b/settings.gradle index e69de29..6cc8768 100644 --- a/settings.gradle +++ b/settings.gradle @@ -0,0 +1,3 @@ +rootProject.name = 'rendering' + +include 'example' \ No newline at end of file diff --git a/src/.gitignore b/src/.gitignore deleted file mode 100644 index 30821b6..0000000 --- a/src/.gitignore +++ /dev/null @@ -1 +0,0 @@ -!docs \ No newline at end of file diff --git a/src/docs/guide/1. Introduction.gdoc b/src/docs/guide/1. Introduction.gdoc deleted file mode 100644 index 4a341c6..0000000 --- a/src/docs/guide/1. Introduction.gdoc +++ /dev/null @@ -1,15 +0,0 @@ -This plugin adds additional rendering capabilities to Grails applications via the "XHTML Renderer":https://xhtmlrenderer.dev.java.net/ library. - -Rendering is either done directly via @«format»RenderingService@ services ... - -{code} -ByteArrayOutputStream bytes = pdfRenderingService.render(template: "/pdfs/report", model: [data: data]) -{code} - -Or via the @render«format»()@ methods added to controllers ... - -{code} -renderPdf(template: "/pdfs/report", model: [report: reportObject], filename: reportObject.name) -{code} - -The plugin is released under the "Apache License 2.0":http://www.apache.org/licenses/LICENSE-2.0.html license and is produced under the "Grails Plugin Collective":http://gpc.github.com/ . \ No newline at end of file diff --git a/src/docs/guide/2. GSP Considerations.gdoc b/src/docs/guide/2. GSP Considerations.gdoc deleted file mode 100644 index b5b6148..0000000 --- a/src/docs/guide/2. GSP Considerations.gdoc +++ /dev/null @@ -1,20 +0,0 @@ -There are a few things that you do need to be aware of when writing GSPs to be rendered via this plugin. - -h3. Link resources must be resolvable - -All links to resources (e.g. images, css) must be _accessible by the application_ . This is due to the linked resources being accessed by _application_ and not a browser. Depending on your network config in production, this may require some special consideration. - -The rendering engine resolves all relative links relative to the @grails.serverURL@ config property. - -h3. Must be well formed - -The GSP must render to well formed, valid, XHTML. If it does not, a @grails.plugins.rendering.document.XmlParseException@ will be thrown. - -h3. Must declare DOCTYPE - -Without a doctype, you are likely to get parse failures due to unresolvable entity references (e.g. @ @). Be sure to declare the XHTML doctype at the start of your GSP like so ... - -{code:lang=xml} - -{code} \ No newline at end of file diff --git a/src/docs/guide/3. Rendering.gdoc b/src/docs/guide/3. Rendering.gdoc deleted file mode 100644 index 4845a1a..0000000 --- a/src/docs/guide/3. Rendering.gdoc +++ /dev/null @@ -1,58 +0,0 @@ -There are four services available for rendering: - -* pdfRenderingService -* gifRenderingService -* pngRenderingService -* jpegRenderingService - -All services have the same method… - -{code:java} -OutputStream render(Map args, OutputStream destination = new ByteArrayOutputStream()) -{code} - -The @args@ define the render operation, with the bytes written to the given output stream. The given output stream is returned from the method. If no @destination@ is provided, the render will write to a @ByteArrayOutputStream@ that is returned. - -Here are some examples: - -{code:java} -// Get the bytes -def bytes = gifRenderingService.render(template: '/images/coupon', model: [serial: 12345]) - -// Render to a file -new File("coupon.jpg").withOutputStream { outputStream -> - jpegRenderingService.render([template: '/images/coupon', model: [serial: 12345]], outputStream) -} -{code} - -For information on rendering to the HTTP response, see [Rendering To The Response|guide:5. Rendering To The Response]. - -h3. Basic Render Arguments - -All rendering methods take a @Map@ argument that specifies which template to render and the model to use (in most cases). - -The following map arguments are common to all rendering methods: - -* @template@ (required) - The template to render -* @model@ (optional) - The model to use -* @plugin@ (optional) - The plug-in containing the template -* @controller@ (optional) - The controller _instance_ or _name_ to resolve the template against (set automatically in provided @render«format»@ methods on controllers). - -h3. Template Resolution - -The plugin uses the same resolution strategy as the @render()@ method in Grails controllers and taglibs. - -That is, - -* template files must start with an underscore (@_template.gsp@) -* template paths starting with "/" are resolved relative to the @views@ directory -* template paths NOT starting with "/" are resolved relative to the @views/«controller»@ directory - -If the @template@ argument does not start with a "/", the @controller@ argument must be provided. The methods added to controllers (e.g. @renderPdf()@) automatically pass the @controller@ param for you. - -h3. Debuging - -To get more visibility about what is going on inside, you can activate the logging within Flying Saucer by providing the system property xr.util-logging.loggingEnabled like so: -{code} -grails -Dxr.util-logging.loggingEnabled=true run-app -{code} diff --git a/src/docs/guide/4. Sizing.gdoc b/src/docs/guide/4. Sizing.gdoc deleted file mode 100644 index 56d5c11..0000000 --- a/src/docs/guide/4. Sizing.gdoc +++ /dev/null @@ -1,41 +0,0 @@ -h3. Documents - -When rendering PDF documents, you can specify the page size via CSS… - -{code} - -{code} - -h3. Images - -The image rendering methods take extra arguments to control the size of the rendered image. The extra arguments are maps containing @width@ or @height@ keys, or both. - -h4. render - -The @render@ argument is the size of the view port that the document is rendered into. This is equivalent to the dimensions of the browser window for html rendering. - -The default value for @render@ is @[width: 10, height: 10000]@ (i.e. 10 pixels wide by 10000 pixels high). - -h4. autosize - -The @autosize@ argument specifies whether to adjust the size of the image to exactly be the rendered content. - -The default value for @autosize@ is @[width: true, height: true]@. - -h4. scale - -The @scale@ argument specifies the factor to scale the image by after initial rendering. For example, the value @[width: 0.5, height: 0.5]@ produces an image half the size of the original render. - -The default value for @autosize@ is null. - -h4. resize - -The @resize@ argument specifies the adjusted mage after initial rendering. For example, the value @[width: 200, height: 400]@ will resize the image to 200 pixels X 400 pixels regardless of the original render size. - -(note that @resize@ & @scale@ are mutually exclusive with @scale@ taking precedence). - -The default value for @resize@ is null. diff --git a/src/docs/guide/5. Rendering To The Response.adoc b/src/docs/guide/5. Rendering To The Response.adoc deleted file mode 100644 index dbb67f6..0000000 --- a/src/docs/guide/5. Rendering To The Response.adoc +++ /dev/null @@ -1,39 +0,0 @@ -= Rendering To The Response - -There are four methods added to all controllers for rendering: - -* renderPdf(Map args) -* renderGif(Map args) -* renderPng(Map args) -* renderJpeg(Map args) - -Each of the methods is equivalent to: - -[source,groovy] ----- -«format»RenderingService.render(args + [controller: this], response) ----- - -All methods take all of the arguments that their respective service's `render()` method take, plus some extras. - -=== Extra Render Arguments - -All rendering methods take a `Map` argument that specifies which template to render and the model to use (in most cases). - -The following map arguments are common to all rendering methods: - -* `filename` (optional) - sets the `Content-Disposition` header with `attachment; filename="$filename"` (asking the browser to download the file with the given filename) -* `contentType` (optional) - the `Content-Type` header value (see Content Type Defaults below) - -=== Default Content Types - -The default content types are: - -* application/pdf -* image/gif -* image/png -* image/jpeg - -=== Large Files/Renders - -See the section on <> for some other arguments that can help with large renders. diff --git a/src/docs/guide/5. Rendering To The Response.gdoc b/src/docs/guide/5. Rendering To The Response.gdoc deleted file mode 100644 index 41cc951..0000000 --- a/src/docs/guide/5. Rendering To The Response.gdoc +++ /dev/null @@ -1,36 +0,0 @@ -There are four methods added to all controllers for rendering: - -* renderPdf(Map args) -* renderGif(Map args) -* renderPng(Map args) -* renderJpeg(Map args) - -Each of the methods is equivalent to… - -{code} -«format»RenderingService.render(args + [controller: this], response) -{code} - -All methods take all of the arguments that their respective service's @render()@ method take, plus some extras. - -h3. Extra Render Arguments - -All rendering methods take a @Map@ argument that specifies which template to render and the model to use (in most cases). - -The following map arguments are common to all rendering methods: - -* @filename@ (option) - sets the @Content-Disposition@ header with @attachment; filename="$filename";@ (asking the browser to download the file with the given filename) -* @contentType@ (optional) - the @Content-Type@ header value (see Content Type Defaults below) - -h3. Default Content Types - -The default content types are… - -* application/pdf -* image/gif -* image/png -* image/jpeg - -h3. Large Files/Renders - -See the section on [caching and performance|guide:6. Caching And Performance] for some other arguments that can help with large renders. \ No newline at end of file diff --git a/src/docs/guide/6. Caching And Performance.gdoc b/src/docs/guide/6. Caching And Performance.gdoc deleted file mode 100644 index bd3f334..0000000 --- a/src/docs/guide/6. Caching And Performance.gdoc +++ /dev/null @@ -1,76 +0,0 @@ -h3. Caching - -Rendering can be an expensive operation so you may need to implement caching (using the excellent [spring-cache:http://grails.org/plugin/springcache] plugin) - -h4. Document Caching - -Rendering works internally by creating a @org.w3c.dom.Document@ instance from the GSP page via the @xhtmlDocumentService@. If you plan to render the same GSP as different output formats, you may want to cache the document. - -{code} -import grails.plugin.springcache.annotations.Cacheable - -class CouponDocumentService { - def xhmlDocumentService - - @Cacheable('couponDocumentCache')@ - class getDocument(serial) { - xhmlDocumentService.createDocument(template: '/coupon', model: [serial: serial]) - } -} -{code} - -All of the render methods can take a @document@ parameter instead of the usual @template@/@model@ properties. - -{code} -class CouponController { - - def couponDocumentService - - def gif = { - def serial = params.id - def document = couponDocumentService.getDocument(serial) - - renderGif(filename: "${serial}.gif", document) - } -} -{code} - -h4. Byte Caching - -You can take things further and actually cache the rendered bytes. - -{code} -import grails.plugin.springcache.annotations.Cacheable - -class CouponGifService { - - def couponDocumentService - def gifRenderingService - - def getGif(serial) { - def document = couponDocumentService.getDocument(serial) - def byteArrayOutputStream = gifRenderingService.gif([:], document) - byteArrayOutputStream.toByteArray() - } -} -{code} - -{code} -class CouponController { - - def couponGifService - - def gif = { - def serial = params.id - def bytes = couponGifService.getGif(serial) - - renderGif(bytes: bytes, filename: "${serial}.gif") - } -} -{code} - -h3. Avoiding Byte Copying - -When rendering to the response, the content is first written to a temp buffer before being written to the response. This is so the number of bytes can be determined and the @Content-Length@ header set (this also applies when passing the @bytes@ directly). - -This copy can be avoided and the render (or bytes) can be written directly to the response output stream. This means that the @Content-Length@ header will not be set unless you manually specify the length via the @contentLength@ property to the render method. \ No newline at end of file diff --git a/src/docs/guide/7. Inline Images.gdoc b/src/docs/guide/7. Inline Images.gdoc deleted file mode 100644 index 0578aab..0000000 --- a/src/docs/guide/7. Inline Images.gdoc +++ /dev/null @@ -1,32 +0,0 @@ -This plugin adds support for inline images via "data uris":http://en.wikipedia.org/wiki/Data_URI_scheme. This is useful for situations where the images you need to imbed in a rendered PDF or image are generated by the application itself. - -For example, your application may generate barcodes that you don't necessarily want to expose but want to include in your generated PDFs or images. Using inline images, you can include the image bytes in the document to be rendered. - -To make this easier, the plugin provides tags to render byte arrays as common image formats (i.e. gif, png and jpeg). - -The tags are under the namespace @rendering@ and are called @inlinePng@, @inlineGif@ and @inlineJpeg@. They all take a single argument, @bytes@, which is a @byte[]@ containing the raw bytes of the images. This will result in an @img@ tag with a @src@ attribute of a suitable data uri. Any other parameters passed to the tag will be expressed as attributes of the resultant @img@ tag. - -Here is an example of how this could be used to include a local (i.e. from the filesystem) image in a generated pdf/image. - -{code} -class SomeController { - - def generate = { - def file = new File("path/to/image.png") - renderPng(template: "thing", model: [imageBytes: file.bytes]) - } - -} -{code} - -In the view… - -{code} - - - -

Below is an inline image

- - - -{code} diff --git a/src/docs/guide/8. Exotic Characters.gdoc b/src/docs/guide/8. Exotic Characters.gdoc deleted file mode 100644 index 260d327..0000000 --- a/src/docs/guide/8. Exotic Characters.gdoc +++ /dev/null @@ -1,18 +0,0 @@ -In most cases, there are no issues with dealing with exotic Unicode characters. However, certain characters will not render in PDF documents without some extra work (the same problem does not exist when rendering images). This is a quirk with the way iText works, which is the library underpinning the PDF generation. - -This "thread":http://www.mail-archive.com/itext-questions@lists.sourceforge.net/msg48788.html explains the issue. - -The solution is to register the font to use with a particular encoding. Because we are using XHTMLRenderer we can specify this in CSS as opposed to programatically registering. - -{code} - @font-face { - src: url(path/to/arial.ttf); - -fs-pdf-font-embed: embed; - -fs-pdf-font-encoding: cp1250; - } - body { - font-family: "Arial Unicode MS", Arial, sans-serif; - } -{code} - -See "this page":http://pigeonholdings.com/projects/flyingsaucer/R8/doc/guide/users-guide-R8.html#xil_44 for details on these CSS directives. \ No newline at end of file diff --git a/src/docs/ref/Controller/renderGif.adoc b/src/docs/ref/Controller/renderGif.adoc deleted file mode 100644 index e858252..0000000 --- a/src/docs/ref/Controller/renderGif.adoc +++ /dev/null @@ -1,16 +0,0 @@ -= renderGif - -== Purpose - -== Examples - -[source,java] ----- -foo.renderGif(map) ----- - -== Description - -Arguments: - -* `map` \ No newline at end of file diff --git a/src/docs/ref/Controller/renderGif.gdoc b/src/docs/ref/Controller/renderGif.gdoc deleted file mode 100644 index a42a392..0000000 --- a/src/docs/ref/Controller/renderGif.gdoc +++ /dev/null @@ -1,21 +0,0 @@ - -h1. renderGif - -h2. Purpose - - - -h2. Examples - -{code:java} -foo.renderGif(map) -{code} - -h2. Description - - - -Arguments: - -[* @map@ -] diff --git a/src/docs/ref/Controller/renderJpeg.adoc b/src/docs/ref/Controller/renderJpeg.adoc deleted file mode 100644 index cfe62a7..0000000 --- a/src/docs/ref/Controller/renderJpeg.adoc +++ /dev/null @@ -1,16 +0,0 @@ -= renderJpeg - -== Purpose - -== Examples - -[source,java] ----- -foo.renderJpeg(map) ----- - -== Description - -Arguments: - -* `map` \ No newline at end of file diff --git a/src/docs/ref/Controller/renderJpeg.gdoc b/src/docs/ref/Controller/renderJpeg.gdoc deleted file mode 100644 index 5b08fb2..0000000 --- a/src/docs/ref/Controller/renderJpeg.gdoc +++ /dev/null @@ -1,21 +0,0 @@ - -h1. renderJpeg - -h2. Purpose - - - -h2. Examples - -{code:java} -foo.renderJpeg(map) -{code} - -h2. Description - - - -Arguments: - -[* @map@ -] diff --git a/src/docs/ref/Controller/renderPdf.adoc b/src/docs/ref/Controller/renderPdf.adoc deleted file mode 100644 index 0db6970..0000000 --- a/src/docs/ref/Controller/renderPdf.adoc +++ /dev/null @@ -1,16 +0,0 @@ -= renderPdf - -== Purpose - -== Examples - -[source,java] ----- -foo.renderPdf(map) ----- - -== Description - -Arguments: - -* `map` \ No newline at end of file diff --git a/src/docs/ref/Controller/renderPdf.gdoc b/src/docs/ref/Controller/renderPdf.gdoc deleted file mode 100644 index 497a25a..0000000 --- a/src/docs/ref/Controller/renderPdf.gdoc +++ /dev/null @@ -1,21 +0,0 @@ - -h1. renderPdf - -h2. Purpose - - - -h2. Examples - -{code:java} -foo.renderPdf(map) -{code} - -h2. Description - - - -Arguments: - -[* @map@ -] diff --git a/src/docs/ref/Controller/renderPng.adoc b/src/docs/ref/Controller/renderPng.adoc deleted file mode 100644 index 2dd14f8..0000000 --- a/src/docs/ref/Controller/renderPng.adoc +++ /dev/null @@ -1,16 +0,0 @@ -= renderPng - -== Purpose - -== Examples - -[source,java] ----- -foo.renderPng(map) ----- - -== Description - -Arguments: - -* `map` \ No newline at end of file diff --git a/src/docs/ref/Controller/renderPng.gdoc b/src/docs/ref/Controller/renderPng.gdoc deleted file mode 100644 index 234dde4..0000000 --- a/src/docs/ref/Controller/renderPng.gdoc +++ /dev/null @@ -1,21 +0,0 @@ - -h1. renderPng - -h2. Purpose - - - -h2. Examples - -{code:java} -foo.renderPng(map) -{code} - -h2. Description - - - -Arguments: - -[* @map@ -] diff --git a/src/integration-test/groovy/grails/plugins/rendering/ControllerRelativeTemplateSpec.groovy b/src/integration-test/groovy/grails/plugins/rendering/ControllerRelativeTemplateSpec.groovy deleted file mode 100644 index 29d5968..0000000 --- a/src/integration-test/groovy/grails/plugins/rendering/ControllerRelativeTemplateSpec.groovy +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2010 Grails Plugin Collective - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package grails.plugins.rendering - - -import org.springframework.http.HttpMethod -import org.springframework.web.client.RestTemplate -import spock.lang.Specification - -class ControllerRelativeTemplateSpec extends Specification { - - def accessingControllerRelativeTemplateWorks() { - when: - RestTemplate restTemplate = new RestTemplate() - def resp = restTemplate.exchange( - "http://localhost:8080/rendering/relative", - HttpMethod.GET, - null, - String - ) - then: - resp.statusCode.value() == 200 - } -} diff --git a/src/integration-test/groovy/grails/plugins/rendering/RenderingGrailsPluginSpec.groovy b/src/integration-test/groovy/grails/plugins/rendering/RenderingGrailsPluginSpec.groovy deleted file mode 100644 index 5693291..0000000 --- a/src/integration-test/groovy/grails/plugins/rendering/RenderingGrailsPluginSpec.groovy +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2010 Grails Plugin Collective - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package grails.plugins.rendering - -import grails.testing.mixin.integration.Integration -import grails.util.Holders -import spock.lang.Ignore -import spock.lang.Specification -import spock.lang.Unroll - -@Integration -class RenderingGrailsPluginSpec extends Specification { - - def grailsApplication - - @Ignore - @Unroll("rendering #action works from controllers and survives a reload") - def supportReloadingControllerClasses() { - when: - def controller = createController() - controller."$action"() - then: - notThrown(MissingMethodException) - when: - Holders.pluginManager.informOfClassChange(reloadControllerClass()) - controller = createController() - and: - controller."$action"() - then: - notThrown(MissingMethodException) - where: - action << ['pdf', 'gif', 'png', 'jpeg'] - } - - protected createController() { - grailsApplication.mainContext['RenderingController'] - } - - protected reloadControllerClass() { - grailsApplication.classLoader.reloadClass('RenderingController') - } -} diff --git a/src/docs/guide/1. Introduction.adoc b/src/main/asciidoc/1. Introduction.adoc similarity index 80% rename from src/docs/guide/1. Introduction.adoc rename to src/main/asciidoc/1. Introduction.adoc index a5887c4..975b78b 100644 --- a/src/docs/guide/1. Introduction.adoc +++ b/src/main/asciidoc/1. Introduction.adoc @@ -9,11 +9,11 @@ Rendering is either done directly via `«format»RenderingService` services ... ByteArrayOutputStream bytes = pdfRenderingService.render(template: "/pdfs/report", model: [data: data]) ---- -Or via the `render«format»()` methods added to controllers ... +Or via the `render«format»()` methods in `RenderingTrait` that is added to controllers ... [source,groovy] ---- renderPdf(template: "/pdfs/report", model: [report: reportObject], filename: reportObject.name) ---- -The plugin is released under the http://www.apache.org/licenses/LICENSE-2.0.html[Apache License 2.0] license and is produced under the http://gpc.github.com/[Grails Plugin Collective]. +The plugin is released under the http://www.apache.org/licenses/LICENSE-2.0.html[Apache License 2.0] license and is produced under the http://github.com/gpc[Grails Plugin Collective]. diff --git a/src/docs/guide/2. GSP Considerations.adoc b/src/main/asciidoc/2. GSP Considerations.adoc similarity index 91% rename from src/docs/guide/2. GSP Considerations.adoc rename to src/main/asciidoc/2. GSP Considerations.adoc index 7d06ec3..c941050 100644 --- a/src/docs/guide/2. GSP Considerations.adoc +++ b/src/main/asciidoc/2. GSP Considerations.adoc @@ -2,17 +2,17 @@ There are a few things that you do need to be aware of when writing GSPs to be rendered via this plugin. -=== Link resources must be resolvable +== Link resources must be resolvable All links to resources (e.g. images, css) must be _accessible by the application_. This is due to the linked resources being accessed by _application_ and not a browser. Depending on your network setup, ensure resources are available. The rendering engine resolves all relative links relative to the `grails.serverURL` config property. -=== Must be well formed +== Must be well formed The GSP must render to well formed, valid, XHTML. If it does not, a `grails.plugins.rendering.document.XmlParseException` will be thrown. -=== Must declare DOCTYPE +== Must declare DOCTYPE Without a doctype, you are likely to get parse failures due to unresolvable entity references (e.g. ` `). Be sure to declare the XHTML doctype at the start of your GSP like so: diff --git a/src/docs/guide/3. Rendering.adoc b/src/main/asciidoc/3. Rendering.adoc similarity index 95% rename from src/docs/guide/3. Rendering.adoc rename to src/main/asciidoc/3. Rendering.adoc index 52fac9f..2488b9a 100644 --- a/src/docs/guide/3. Rendering.adoc +++ b/src/main/asciidoc/3. Rendering.adoc @@ -1,11 +1,12 @@ +[#rendering] = Rendering There are four services available for rendering: -* pdfRenderingService -* gifRenderingService -* pngRenderingService -* jpegRenderingService +* `pdfRenderingService` +* `gifRenderingService` +* `pngRenderingService` +* `jpegRenderingService` All services have the same method: diff --git a/src/docs/guide/4. Sizing.adoc b/src/main/asciidoc/4. Sizing.adoc similarity index 94% rename from src/docs/guide/4. Sizing.adoc rename to src/main/asciidoc/4. Sizing.adoc index 9a7985d..425b988 100644 --- a/src/docs/guide/4. Sizing.adoc +++ b/src/main/asciidoc/4. Sizing.adoc @@ -1,10 +1,10 @@ = Sizing -=== Documents +== Documents When rendering PDF documents, you can specify the page size via CSS: -[source,css] +[source,html] ---- ---- -=== Images +== Images The image rendering methods take extra arguments to control the size of the rendered image. The extra arguments are maps containing `width` or `height` keys, or both. -==== render +=== render The `render` argument is the size of the view port that the document is rendered into. This is equivalent to the dimensions of the browser window for html rendering. The default value for `render` is `[width: 10, height: 10000]` (i.e. 10 pixels wide by 10000 pixels high). -==== autosize +=== autosize The `autosize` argument specifies whether to adjust the size of the image to exactly be the rendered content. The default value for `autosize` is `[width: true, height: true]`. -==== scale +=== scale The `scale` argument specifies the factor to scale the image by after initial rendering. For example, the value `[width: 0.5, height: 0.5]` produces an image half the size of the original render. The default value for `scale` is `null`. -==== resize +=== resize The `resize` argument specifies the adjusted image after initial rendering. For example, the value `[width: 200, height: 400]` will resize the image to 200 pixels x 400 pixels regardless of the original size. diff --git a/src/main/asciidoc/5. Rendering To The Response.adoc b/src/main/asciidoc/5. Rendering To The Response.adoc new file mode 100644 index 0000000..92fe3d3 --- /dev/null +++ b/src/main/asciidoc/5. Rendering To The Response.adoc @@ -0,0 +1,50 @@ += Rendering To The Response + +Rendering is available via the `RenderingTrait` that is automatically applied to Controllers + +[source,groovy] +---- +class MyController { + def action() { + renderPdf(template: 'simple-template') + } +} +---- + +== Methods in `RenderingTrait` + +* `renderPdf(Map args)` +* `renderGif(Map args)` +* `renderPng(Map args)` +* `renderJpeg(Map args)` + +Each of the methods is equivalent to: + +[source,groovy] +---- +«format»RenderingService.render(args + [controller: this], response) +---- + +All methods take all the arguments that their respective service's `render()` method take, plus some extras. + +== Extra Render Arguments + +All rendering methods take a `Map` argument that specifies which template to render and the model to use (in most cases). + +The following map arguments are common to all rendering methods: + +* `filename` (optional) - sets the `Content-Disposition` header with `attachment; filename="$filename"` (asking the browser to download the file with the given filename) +* `contentType` (optional) - the `Content-Type` header value (see Content Type Defaults below) + +== Default Content Types + +The default content types are: + +* `application/pdf` +* `image/gif` +* `image/png` +* `image/jpeg` + +== Large Files/Renders + +See the section on <> for some other arguments that can help with large renders. diff --git a/src/docs/guide/6. Caching And Performance.adoc b/src/main/asciidoc/6. Caching And Performance.adoc similarity index 90% rename from src/docs/guide/6. Caching And Performance.adoc rename to src/main/asciidoc/6. Caching And Performance.adoc index d8e6a8b..6d2124c 100644 --- a/src/docs/guide/6. Caching And Performance.adoc +++ b/src/main/asciidoc/6. Caching And Performance.adoc @@ -1,10 +1,11 @@ +[#caching_and_performance] = Caching And Performance -=== Caching +== Caching -Rendering can be an expensive operation so you may need to implement caching (using the excellent http://grails.org/plugin/springcache[spring-cache] plugin). +Rendering can be an expensive operation so you may need to implement caching (using the excellent https://github.com/apache/grails-core/tree/7.0.x/grails-cache[grails-cache] plugin). -==== Document Caching +=== Document Caching Rendering works internally by creating a `org.w3c.dom.Document` instance from the GSP page via the `xhtmlDocumentService`. If you plan to render the same GSP as different output formats, you may want to cache the created Document. @@ -39,7 +40,7 @@ class CouponController { } ---- -==== Byte Caching +=== Byte Caching You can take things further and actually cache the rendered bytes. @@ -75,7 +76,7 @@ class CouponController { } ---- -=== Avoiding Byte Copying +== Avoiding Byte Copying When rendering to the response, the content is first written to a temp buffer before being written to the response. This is so the number of bytes can be determined and the `Content-Length` header can be set. diff --git a/src/docs/guide/7. Inline Images.adoc b/src/main/asciidoc/7. Inline Images.adoc similarity index 82% rename from src/docs/guide/7. Inline Images.adoc rename to src/main/asciidoc/7. Inline Images.adoc index 6f02066..0a272e8 100644 --- a/src/docs/guide/7. Inline Images.adoc +++ b/src/main/asciidoc/7. Inline Images.adoc @@ -1,6 +1,6 @@ = Inline Images -This plugin adds support for inline images via http://en.wikipedia.org/wiki/Data_URI_scheme[data URIs]. This is useful for situations where the images you need to imbed in a rendered PDF or image are not accessible via a URL. +This plugin adds support for inline images via http://en.wikipedia.org/wiki/Data_URI_scheme[data URIs]. This is useful for situations where the images you need to embed in a rendered PDF or image are not accessible via a URL. For example, your application may generate barcodes that you don't necessarily want to expose but want to include in your generated PDFs or images. Using inline images, you can include the image bytes directly in the output. @@ -14,17 +14,17 @@ Here is an example of how this could be used to include a local (i.e. from the f ---- class SomeController { - def generate = { - def file = new File("path/to/image.png") - renderPng(template: "thing", model: [imageBytes: file.bytes]) - } - + def generate() { + URL resource = this.class.getResource("/path/to/image.png") + renderPng(template: "thing", model: [imageBytes: resource.bytes]) + } } ---- In the view ... [source,html] +._thing.gsp ---- diff --git a/src/docs/guide/8. Exotic Characters.adoc b/src/main/asciidoc/8. Exotic Characters.adoc similarity index 78% rename from src/docs/guide/8. Exotic Characters.adoc rename to src/main/asciidoc/8. Exotic Characters.adoc index d4f2a8d..6d5d9cb 100644 --- a/src/docs/guide/8. Exotic Characters.adoc +++ b/src/main/asciidoc/8. Exotic Characters.adoc @@ -4,7 +4,7 @@ In most cases, there are no issues with dealing with exotic Unicode characters. This http://www.mail-archive.com/itext-questions@lists.sourceforge.net/msg48788.html[thread] explains the issue. -The solution is to register the font to use with a particular encoding. Because we are using XHTMLRenderer we can specify this in CSS as opposed to programatically registering. +The solution is to register the font to use with a particular encoding. Because we are using XHTMLRenderer we can specify this in CSS as opposed to programmatically registering. [source,css] ---- @@ -17,4 +17,4 @@ body { font-family: "Arial Unicode MS", Arial, sans-serif; } ---- -See http://pigeonholdings.com/projects/flyingsaucer/R8/doc/guide/users-guide-R8.html#xil_44[this page] for details on these CSS directives. +See https://flyingsaucerproject.github.io/flyingsaucer/r8/guide/users-guide-R8.html#xil_43[this page] for details on these CSS directives. diff --git a/src/main/asciidoc/index.adoc b/src/main/asciidoc/index.adoc new file mode 100644 index 0000000..8555870 --- /dev/null +++ b/src/main/asciidoc/index.adoc @@ -0,0 +1,15 @@ += Grails Render +:doctype: book +:author: Grails Plugin Collective (GPC) +:source-highlighter: coderay +:numbered: +:imagesdir: ./images + +include::1. Introduction.adoc[leveloffset=2] +include::2. GSP Considerations.adoc[leveloffset=2] +include::3. Rendering.adoc[leveloffset=2] +include::4. Sizing.adoc[leveloffset=2] +include::5. Rendering To The Response.adoc[leveloffset=2] +include::6. Caching And Performance.adoc[leveloffset=2] +include::7. Inline Images.adoc[leveloffset=2] +include::8. Exotic Characters.adoc[leveloffset=2] diff --git a/src/main/groovy/grails/plugins/rendering/GrailsRenderingException.groovy b/src/main/groovy/grails/plugins/rendering/GrailsRenderingException.groovy index 0a9a80a..b4627f5 100644 --- a/src/main/groovy/grails/plugins/rendering/GrailsRenderingException.groovy +++ b/src/main/groovy/grails/plugins/rendering/GrailsRenderingException.groovy @@ -16,10 +16,10 @@ package grails.plugins.rendering -class GrailsRenderingException extends RuntimeException { - - GrailsRenderingException(CharSequence message, Throwable cause = null) { - super(message.toString(), cause) - } +import groovy.transform.CompileStatic +import groovy.transform.InheritConstructors -} \ No newline at end of file +@CompileStatic +@InheritConstructors +class GrailsRenderingException extends RuntimeException { +} diff --git a/src/main/groovy/grails/plugins/rendering/RenderingException.groovy b/src/main/groovy/grails/plugins/rendering/RenderingException.groovy index f92e352..3591cbb 100644 --- a/src/main/groovy/grails/plugins/rendering/RenderingException.groovy +++ b/src/main/groovy/grails/plugins/rendering/RenderingException.groovy @@ -16,9 +16,12 @@ package grails.plugins.rendering +import groovy.transform.CompileStatic + +@CompileStatic class RenderingException extends GrailsRenderingException { - RenderingException(cause) { + RenderingException(Exception cause) { super("Render failure", cause) } diff --git a/src/main/groovy/grails/plugins/rendering/RenderingGrailsPlugin.groovy b/src/main/groovy/grails/plugins/rendering/RenderingGrailsPlugin.groovy index 6173a0b..a578544 100644 --- a/src/main/groovy/grails/plugins/rendering/RenderingGrailsPlugin.groovy +++ b/src/main/groovy/grails/plugins/rendering/RenderingGrailsPlugin.groovy @@ -15,33 +15,32 @@ */ package grails.plugins.rendering -import grails.plugins.* +import grails.plugins.Plugin +import groovy.transform.CompileStatic + +@CompileStatic class RenderingGrailsPlugin extends Plugin { - def grailsVersion = "3.0 > *" - - def pluginExcludes = [ - "grails-app/views/**", - "RenderingController**", - "grails-app/services/grails/plugin/rendering/test/**", - "src/groovy/grails/plugin/rendering/test/**", - "plugins/**", - "web-app/**" - ] - - def observe = ["controllers"] - def loadAfter = ["controllers"] - - def author = "Grails Plugin Collective" - def authorEmail = "grails.plugin.collective@gmail.com" - def title = "Grails Rendering" - def description = 'Render GSPs as PDFs, JPEGs, GIFs and PNGs' - def documentation = "http://gpc.github.com/grails-rendering" - - def license = 'APACHE' - def organization = [name: 'Grails Plugin Collective', url: 'http://github.com/gpc'] - def issueManagement = [system: 'JIRA', url: 'http://jira.grails.org/browse/GPRENDERING'] - def scm = [url: 'https://github.com/gpc/grails-rendering'] + def grailsVersion = "7.0 > *" + + def pluginExcludes = [ + "grails-app/views/**", + "example/**" + ] + + def observe = ["controllers"] + def loadAfter = ["controllers"] + + def author = "Grails Plugin Collective" + def authorEmail = "grails.plugin.collective@gmail.com" + def title = "Grails Rendering" + def description = 'Render GSPs as PDFs, JPEGs, GIFs and PNGs' + def documentation = "http://gpc.github.com/grails-rendering" + + def license = 'APACHE' + def organization = [name: 'Grails Plugin Collective', url: 'https://github.com/gpc'] + def issueManagement = [system: 'JIRA', url: 'https://github.com/gpc/rendering/issues'] + def scm = [url: 'https://github.com/gpc/rendering.git'] } diff --git a/src/main/groovy/grails/plugins/rendering/RenderingTrait.groovy b/src/main/groovy/grails/plugins/rendering/RenderingTrait.groovy index dd550a0..6710dee 100644 --- a/src/main/groovy/grails/plugins/rendering/RenderingTrait.groovy +++ b/src/main/groovy/grails/plugins/rendering/RenderingTrait.groovy @@ -21,12 +21,14 @@ import grails.plugins.rendering.image.JpegRenderingService import grails.plugins.rendering.image.PngRenderingService import grails.plugins.rendering.pdf.PdfRenderingService import grails.web.api.ServletAttributes +import groovy.transform.CompileStatic import org.springframework.beans.factory.annotation.Autowired /** * Trait that applies to controllers adding new methods for rendering PDFs, Gif etc. */ @Enhances("Controller") +@CompileStatic trait RenderingTrait extends ServletAttributes{ @Autowired(required = false) diff --git a/src/main/groovy/grails/plugins/rendering/datauri/DataUri.groovy b/src/main/groovy/grails/plugins/rendering/datauri/DataUri.groovy index 8363449..16aa148 100644 --- a/src/main/groovy/grails/plugins/rendering/datauri/DataUri.groovy +++ b/src/main/groovy/grails/plugins/rendering/datauri/DataUri.groovy @@ -16,6 +16,9 @@ package grails.plugins.rendering.datauri +import groovy.transform.CompileStatic + +@CompileStatic class DataUri { // Default values sourced from http://en.wikipedia.org/wiki/Data_URI_scheme @@ -38,7 +41,9 @@ class DataUri { throw new IllegalArgumentException("data url does not contain a ',' delimiter: " + value) } - def (metadata, data) = value.split(",", 2) + def split = value.split(",", 2) + String metadata = split[0] + String data = split[1] if (metadata != "") { processMetadata(metadata.split(';')) } diff --git a/src/main/groovy/grails/plugins/rendering/datauri/DataUriAwareITextUserAgent.groovy b/src/main/groovy/grails/plugins/rendering/datauri/DataUriAwareITextUserAgent.groovy deleted file mode 100644 index 1abd2d4..0000000 --- a/src/main/groovy/grails/plugins/rendering/datauri/DataUriAwareITextUserAgent.groovy +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2010 Grails Plugin Collective - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package grails.plugins.rendering.datauri - -import grails.util.GrailsUtil - -import org.slf4j.LoggerFactory -import org.xhtmlrenderer.pdf.ITextFSImage -import org.xhtmlrenderer.pdf.ITextOutputDevice -import org.xhtmlrenderer.pdf.ITextUserAgent -import org.xhtmlrenderer.resource.ImageResource - -import com.lowagie.text.Image - -class DataUriAwareITextUserAgent extends ITextUserAgent { - - private static log = LoggerFactory.getLogger(DataUriAwareITextUserAgent) - - DataUriAwareITextUserAgent(ITextOutputDevice outputDevice) { - super(outputDevice) - } - - ImageResource getImageResource(String uri) { - def resource = _imageCache.get(uri) - if (resource) { - return resource - } - - if (DataUri.isDataUri(uri)) { - def dataUri = new DataUri(uri) - if (dataUri.mimeType.startsWith("image/")) { - try { - def image = Image.getInstance(dataUri.bytes) - def factor = sharedContext.dotsPerPixel - image.scaleAbsolute((image.plainWidth * factor) as float, (image.plainHeight * factor) as float) - resource = new ImageResource(uri, new ITextFSImage(image)) - _imageCache.put(uri, resource) - resource - } catch (Exception e) { - GrailsUtil.deepSanitize(e) - log.error("exception creating image from data uri (will use empty image): $dataUri", e) - new ImageResource(uri, null) - } - } else { - log.error("data uri has a non image mime type (will use empty image): $dataUri") - new ImageResource(uri, null) - } - } else { - super.getImageResource(uri) - } - } -} diff --git a/src/main/groovy/grails/plugins/rendering/datauri/DataUriAwareNaiveUserAgent.groovy b/src/main/groovy/grails/plugins/rendering/datauri/DataUriAwareNaiveUserAgent.groovy index cffd1e0..f77c0b2 100644 --- a/src/main/groovy/grails/plugins/rendering/datauri/DataUriAwareNaiveUserAgent.groovy +++ b/src/main/groovy/grails/plugins/rendering/datauri/DataUriAwareNaiveUserAgent.groovy @@ -16,26 +16,27 @@ package grails.plugins.rendering.datauri -import org.slf4j.LoggerFactory +import groovy.transform.CompileStatic +import groovy.util.logging.Slf4j import org.xhtmlrenderer.swing.NaiveUserAgent +@Slf4j +@CompileStatic class DataUriAwareNaiveUserAgent extends NaiveUserAgent { - private static log = LoggerFactory.getLogger(this) + protected InputStream resolveAndOpenStream(String uri) { + if (DataUri.isDataUri(uri)) { + new DataUri(uri).inputStream + } else { + super.resolveAndOpenStream(uri) + } + } - protected InputStream resolveAndOpenStream(String uri) { - if (DataUri.isDataUri(uri)) { - new DataUri(uri).inputStream - } else { - super.resolveAndOpenStream(uri) - } - } - - String resolveURI(String uri) { - if (DataUri.isDataUri(uri)) { - uri - } else { - super.resolveURI(uri) - } - } + String resolveURI(String uri) { + if (DataUri.isDataUri(uri)) { + uri + } else { + super.resolveURI(uri) + } + } } diff --git a/src/main/groovy/grails/plugins/rendering/document/RenderEnvironment.groovy b/src/main/groovy/grails/plugins/rendering/document/RenderEnvironment.groovy index fca586f..63f5efb 100644 --- a/src/main/groovy/grails/plugins/rendering/document/RenderEnvironment.groovy +++ b/src/main/groovy/grails/plugins/rendering/document/RenderEnvironment.groovy @@ -1,7 +1,7 @@ package grails.plugins.rendering.document +import grails.util.Environment import grails.util.GrailsWebMockUtil - import org.grails.web.servlet.WrappedResponseHolder import org.springframework.context.ApplicationContext import org.springframework.web.context.request.RequestContextHolder @@ -11,69 +11,75 @@ import org.springframework.web.servlet.support.RequestContextUtils class RenderEnvironment { - final Writer out - final Locale locale - final ApplicationContext applicationContext - - private originalRequestAttributes - private renderRequestAttributes - - private originalOut - - RenderEnvironment(ApplicationContext applicationContext, Writer out, Locale locale = null) { - this.out = out - this.locale = locale - this.applicationContext = applicationContext - } - - private init() { - originalRequestAttributes = RequestContextHolder.getRequestAttributes() - renderRequestAttributes = GrailsWebMockUtil.bindMockWebRequest(applicationContext) - - if (originalRequestAttributes) { - renderRequestAttributes.controllerName = originalRequestAttributes.controllerName - } - - def renderLocale - if (locale) { - renderLocale = locale - } else if (originalRequestAttributes) { - renderLocale = RequestContextUtils.getLocale(originalRequestAttributes.request) - } - - renderRequestAttributes.request.setAttribute(DispatcherServlet.LOCALE_RESOLVER_ATTRIBUTE, - new FixedLocaleResolver(defaultLocale: renderLocale)) - - renderRequestAttributes.setOut(out) - WrappedResponseHolder.wrappedResponse = renderRequestAttributes.currentResponse - } - - private close() { - RequestContextHolder.setRequestAttributes(originalRequestAttributes) // null ok - WrappedResponseHolder.wrappedResponse = originalRequestAttributes?.currentResponse - } - - /** - * Establish an environment inheriting the locale of the current request if there is one - */ - static with(ApplicationContext applicationContext, Writer out, Closure block) { - with(applicationContext, out, null, block) - } - - /** - * Establish an environment with a specific locale - */ - static with(ApplicationContext applicationContext, Writer out, Locale locale, Closure block) { - def env = new RenderEnvironment(applicationContext, out, locale) - env.init() - try { - block(env) - } finally { - env.close() - } - } - - String getControllerName() { - renderRequestAttributes.controllerName - } + final Writer out + final Locale locale + final ApplicationContext applicationContext + + private originalRequestAttributes + private renderRequestAttributes + + private originalOut + + RenderEnvironment(ApplicationContext applicationContext, Writer out, Locale locale = null) { + this.out = out + this.locale = locale + this.applicationContext = applicationContext + } + + private init() { + if (Environment.current == Environment.TEST) { + originalRequestAttributes = RequestContextHolder.getRequestAttributes() + renderRequestAttributes = GrailsWebMockUtil.bindMockWebRequest(applicationContext) + + if (originalRequestAttributes) { + renderRequestAttributes.controllerName = originalRequestAttributes.controllerName + } + + def renderLocale + if (locale) { + renderLocale = locale + } else if (originalRequestAttributes) { + renderLocale = RequestContextUtils.getLocale(originalRequestAttributes.request) + } + + renderRequestAttributes.request.setAttribute(DispatcherServlet.LOCALE_RESOLVER_ATTRIBUTE, + new FixedLocaleResolver(defaultLocale: renderLocale)) + + renderRequestAttributes.setOut(out) + WrappedResponseHolder.wrappedResponse = renderRequestAttributes.currentResponse + + } + + } + + private close() { + if (originalRequestAttributes) { + RequestContextHolder.setRequestAttributes(originalRequestAttributes) // null ok + WrappedResponseHolder.wrappedResponse = originalRequestAttributes?.currentResponse + } + } + + /** + * Establish an environment inheriting the locale of the current request if there is one + */ + static with(ApplicationContext applicationContext, Writer out, Closure block) { + with(applicationContext, out, null, block) + } + + /** + * Establish an environment with a specific locale + */ + static with(ApplicationContext applicationContext, Writer out, Locale locale, Closure block) { + def env = new RenderEnvironment(applicationContext, out, locale) + env.init() + try { + block(env) + } finally { + env.close() + } + } + + String getControllerName() { + renderRequestAttributes.controllerName + } } diff --git a/src/main/groovy/grails/plugins/rendering/document/UnknownTemplateException.groovy b/src/main/groovy/grails/plugins/rendering/document/UnknownTemplateException.groovy index 6b8e374..7f9ad22 100644 --- a/src/main/groovy/grails/plugins/rendering/document/UnknownTemplateException.groovy +++ b/src/main/groovy/grails/plugins/rendering/document/UnknownTemplateException.groovy @@ -17,7 +17,9 @@ package grails.plugins.rendering.document import grails.plugins.rendering.GrailsRenderingException +import groovy.transform.CompileStatic +@CompileStatic class UnknownTemplateException extends GrailsRenderingException { UnknownTemplateException(String template, String plugin = null) { diff --git a/src/main/groovy/grails/plugins/rendering/document/XmlParseException.groovy b/src/main/groovy/grails/plugins/rendering/document/XmlParseException.groovy index 0389659..826e816 100644 --- a/src/main/groovy/grails/plugins/rendering/document/XmlParseException.groovy +++ b/src/main/groovy/grails/plugins/rendering/document/XmlParseException.groovy @@ -17,10 +17,17 @@ package grails.plugins.rendering.document import grails.plugins.rendering.GrailsRenderingException +import groovy.transform.CompileStatic +import org.xml.sax.InputSource +@CompileStatic class XmlParseException extends GrailsRenderingException { - XmlParseException(xml, cause) { + XmlParseException(String xml, Exception cause) { + super("Could not parse: $xml", cause) + } + + XmlParseException(InputSource xml, Exception cause) { super("Could not parse: $xml", cause) } diff --git a/travis-build.sh b/travis-build.sh deleted file mode 100755 index 7c01178..0000000 --- a/travis-build.sh +++ /dev/null @@ -1,66 +0,0 @@ -#!/bin/bash -set -e -rm -rf *.zip -./gradlew clean test assemble - -filename=$(find build/libs -name "*.jar" | head -1) -filename=$(basename "$filename") - -EXIT_STATUS=0 -echo "Publishing archives for branch $TRAVIS_BRANCH" -if [[ -n $TRAVIS_TAG ]] || [[ $TRAVIS_BRANCH == 'master' && $TRAVIS_PULL_REQUEST == 'false' ]]; then - - echo "Publishing archives" - - if [[ -n $TRAVIS_TAG ]]; then - ./gradlew bintrayUpload || EXIT_STATUS=$? - else - ./gradlew publish || EXIT_STATUS=$? - fi - - ./gradlew docs || EXIT_STATUS=$? - - git config --global user.name "$GIT_NAME" - git config --global user.email "$GIT_EMAIL" - git config --global credential.helper "store --file=~/.git-credentials" - echo "https://$GH_TOKEN:@github.com" > ~/.git-credentials - - git clone https://${GH_TOKEN}@github.com/${TRAVIS_REPO_SLUG}.git -b gh-pages gh-pages --single-branch > /dev/null - cd gh-pages - - # If this is the master branch then update the snapshot - if [[ $TRAVIS_BRANCH == 'master' ]]; then - mkdir -p snapshot - cp -r ../build/docs/manual/. ./snapshot/ - - git add snapshot/* - fi - - # If there is a tag present then this becomes the latest - if [[ -n $TRAVIS_TAG ]]; then - mkdir -p latest - cp -r ../build/docs/manual/. ./latest/ - git add latest/* - - version="$TRAVIS_TAG" - version=${version:1} - majorVersion=${version:0:4} - majorVersion="${majorVersion}x" - - mkdir -p "$version" - cp -r ../build/docs/manual/. "./$version/" - git add "$version/*" - - mkdir -p "$majorVersion" - cp -r ../build/docs/manual/. "./$majorVersion/" - git add "$majorVersion/*" - - fi - - git commit -a -m "Updating docs for Travis build: https://travis-ci.org/$TRAVIS_REPO_SLUG/builds/$TRAVIS_BUILD_ID" - git push origin HEAD - cd .. - rm -rf gh-pages -fi - -exit $EXIT_STATUS \ No newline at end of file diff --git a/web-app/WEB-INF/applicationContext.xml b/web-app/WEB-INF/applicationContext.xml deleted file mode 100644 index 6f42796..0000000 --- a/web-app/WEB-INF/applicationContext.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - - - Grails application factory bean - - - - - - A bean that manages Grails plugins - - - - - - - - - - - - - - - - - - classpath*:**/grails-app/**/*.groovy - - - - - - utf-8 - - - \ No newline at end of file diff --git a/web-app/WEB-INF/sitemesh.xml b/web-app/WEB-INF/sitemesh.xml deleted file mode 100644 index a547b41..0000000 --- a/web-app/WEB-INF/sitemesh.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/web-app/WEB-INF/tld/c.tld b/web-app/WEB-INF/tld/c.tld deleted file mode 100644 index 22698c9..0000000 --- a/web-app/WEB-INF/tld/c.tld +++ /dev/null @@ -1,563 +0,0 @@ - - - - - JSTL 1.1 core library - JSTL core - 1.1 - c - http://java.sun.com/jsp/jstl/core - - - - Provides core validation features for JSTL tags. - - - org.apache.taglibs.standard.tlv.JstlCoreTLV - - - - - - Catches any Throwable that occurs in its body and optionally - exposes it. - - catch - org.apache.taglibs.standard.tag.common.core.CatchTag - JSP - - -Name of the exported scoped variable for the -exception thrown from a nested action. The type of the -scoped variable is the type of the exception thrown. - - var - false - false - - - - - - Simple conditional tag that establishes a context for - mutually exclusive conditional operations, marked by - <when> and <otherwise> - - choose - org.apache.taglibs.standard.tag.common.core.ChooseTag - JSP - - - - - Simple conditional tag, which evalutes its body if the - supplied condition is true and optionally exposes a Boolean - scripting variable representing the evaluation of this condition - - if - org.apache.taglibs.standard.tag.rt.core.IfTag - JSP - - -The test condition that determines whether or -not the body content should be processed. - - test - true - true - boolean - - - -Name of the exported scoped variable for the -resulting value of the test condition. The type -of the scoped variable is Boolean. - - var - false - false - - - -Scope for var. - - scope - false - false - - - - - - Retrieves an absolute or relative URL and exposes its contents - to either the page, a String in 'var', or a Reader in 'varReader'. - - import - org.apache.taglibs.standard.tag.rt.core.ImportTag - org.apache.taglibs.standard.tei.ImportTEI - JSP - - -The URL of the resource to import. - - url - true - true - - - -Name of the exported scoped variable for the -resource's content. The type of the scoped -variable is String. - - var - false - false - - - -Scope for var. - - scope - false - false - - - -Name of the exported scoped variable for the -resource's content. The type of the scoped -variable is Reader. - - varReader - false - false - - - -Name of the context when accessing a relative -URL resource that belongs to a foreign -context. - - context - false - true - - - -Character encoding of the content at the input -resource. - - charEncoding - false - true - - - - - - The basic iteration tag, accepting many different - collection types and supporting subsetting and other - functionality - - forEach - org.apache.taglibs.standard.tag.rt.core.ForEachTag - org.apache.taglibs.standard.tei.ForEachTEI - JSP - - -Collection of items to iterate over. - - items - false - true - java.lang.Object - - - -If items specified: -Iteration begins at the item located at the -specified index. First item of the collection has -index 0. -If items not specified: -Iteration begins with index set at the value -specified. - - begin - false - true - int - - - -If items specified: -Iteration ends at the item located at the -specified index (inclusive). -If items not specified: -Iteration ends when index reaches the value -specified. - - end - false - true - int - - - -Iteration will only process every step items of -the collection, starting with the first one. - - step - false - true - int - - - -Name of the exported scoped variable for the -current item of the iteration. This scoped -variable has nested visibility. Its type depends -on the object of the underlying collection. - - var - false - false - - - -Name of the exported scoped variable for the -status of the iteration. Object exported is of type -javax.servlet.jsp.jstl.core.LoopTagStatus. This scoped variable has nested -visibility. - - varStatus - false - false - - - - - - Iterates over tokens, separated by the supplied delimeters - - forTokens - org.apache.taglibs.standard.tag.rt.core.ForTokensTag - JSP - - -String of tokens to iterate over. - - items - true - true - java.lang.String - - - -The set of delimiters (the characters that -separate the tokens in the string). - - delims - true - true - java.lang.String - - - -Iteration begins at the token located at the -specified index. First token has index 0. - - begin - false - true - int - - - -Iteration ends at the token located at the -specified index (inclusive). - - end - false - true - int - - - -Iteration will only process every step tokens -of the string, starting with the first one. - - step - false - true - int - - - -Name of the exported scoped variable for the -current item of the iteration. This scoped -variable has nested visibility. - - var - false - false - - - -Name of the exported scoped variable for the -status of the iteration. Object exported is of -type -javax.servlet.jsp.jstl.core.LoopTag -Status. This scoped variable has nested -visibility. - - varStatus - false - false - - - - - - Like <%= ... >, but for expressions. - - out - org.apache.taglibs.standard.tag.rt.core.OutTag - JSP - - -Expression to be evaluated. - - value - true - true - - - -Default value if the resulting value is null. - - default - false - true - - - -Determines whether characters <,>,&,'," in the -resulting string should be converted to their -corresponding character entity codes. Default value is -true. - - escapeXml - false - true - - - - - - - Subtag of <choose> that follows <when> tags - and runs only if all of the prior conditions evaluated to - 'false' - - otherwise - org.apache.taglibs.standard.tag.common.core.OtherwiseTag - JSP - - - - - Adds a parameter to a containing 'import' tag's URL. - - param - org.apache.taglibs.standard.tag.rt.core.ParamTag - JSP - - -Name of the query string parameter. - - name - true - true - - - -Value of the parameter. - - value - false - true - - - - - - Redirects to a new URL. - - redirect - org.apache.taglibs.standard.tag.rt.core.RedirectTag - JSP - - -The URL of the resource to redirect to. - - url - false - true - - - -Name of the context when redirecting to a relative URL -resource that belongs to a foreign context. - - context - false - true - - - - - - Removes a scoped variable (from a particular scope, if specified). - - remove - org.apache.taglibs.standard.tag.common.core.RemoveTag - empty - - -Name of the scoped variable to be removed. - - var - true - false - - - -Scope for var. - - scope - false - false - - - - - - Sets the result of an expression evaluation in a 'scope' - - set - org.apache.taglibs.standard.tag.rt.core.SetTag - JSP - - -Name of the exported scoped variable to hold the value -specified in the action. The type of the scoped variable is -whatever type the value expression evaluates to. - - var - false - false - - - -Expression to be evaluated. - - value - false - true - - - -Target object whose property will be set. Must evaluate to -a JavaBeans object with setter property property, or to a -java.util.Map object. - - target - false - true - - - -Name of the property to be set in the target object. - - property - false - true - - - -Scope for var. - - scope - false - false - - - - - - Creates a URL with optional query parameters. - - url - org.apache.taglibs.standard.tag.rt.core.UrlTag - JSP - - -Name of the exported scoped variable for the -processed url. The type of the scoped variable is -String. - - var - false - false - - - -Scope for var. - - scope - false - false - - - -URL to be processed. - - value - false - true - - - -Name of the context when specifying a relative URL -resource that belongs to a foreign context. - - context - false - true - - - - - - Subtag of <choose> that includes its body if its - condition evalutes to 'true' - - when - org.apache.taglibs.standard.tag.rt.core.WhenTag - JSP - - -The test condition that determines whether or not the -body content should be processed. - - test - true - true - boolean - - - - diff --git a/web-app/WEB-INF/tld/fmt.tld b/web-app/WEB-INF/tld/fmt.tld deleted file mode 100644 index 3b9a54a..0000000 --- a/web-app/WEB-INF/tld/fmt.tld +++ /dev/null @@ -1,671 +0,0 @@ - - - - - JSTL 1.1 i18n-capable formatting library - JSTL fmt - 1.1 - fmt - http://java.sun.com/jsp/jstl/fmt - - - - Provides core validation features for JSTL tags. - - - org.apache.taglibs.standard.tlv.JstlFmtTLV - - - - - - Sets the request character encoding - - requestEncoding - org.apache.taglibs.standard.tag.rt.fmt.RequestEncodingTag - empty - - -Name of character encoding to be applied when -decoding request parameters. - - value - false - true - - - - - - Stores the given locale in the locale configuration variable - - setLocale - org.apache.taglibs.standard.tag.rt.fmt.SetLocaleTag - empty - - -A String value is interpreted as the -printable representation of a locale, which -must contain a two-letter (lower-case) -language code (as defined by ISO-639), -and may contain a two-letter (upper-case) -country code (as defined by ISO-3166). -Language and country codes must be -separated by hyphen (-) or underscore -(_). - - value - true - true - - - -Vendor- or browser-specific variant. -See the java.util.Locale javadocs for -more information on variants. - - variant - false - true - - - -Scope of the locale configuration variable. - - scope - false - false - - - - - - Specifies the time zone for any time formatting or parsing actions - nested in its body - - timeZone - org.apache.taglibs.standard.tag.rt.fmt.TimeZoneTag - JSP - - -The time zone. A String value is interpreted as -a time zone ID. This may be one of the time zone -IDs supported by the Java platform (such as -"America/Los_Angeles") or a custom time zone -ID (such as "GMT-8"). See -java.util.TimeZone for more information on -supported time zone formats. - - value - true - true - - - - - - Stores the given time zone in the time zone configuration variable - - setTimeZone - org.apache.taglibs.standard.tag.rt.fmt.SetTimeZoneTag - empty - - -The time zone. A String value is interpreted as -a time zone ID. This may be one of the time zone -IDs supported by the Java platform (such as -"America/Los_Angeles") or a custom time zone -ID (such as "GMT-8"). See java.util.TimeZone for -more information on supported time zone -formats. - - value - true - true - - - -Name of the exported scoped variable which -stores the time zone of type -java.util.TimeZone. - - var - false - false - - - -Scope of var or the time zone configuration -variable. - - scope - false - false - - - - - - Loads a resource bundle to be used by its tag body - - bundle - org.apache.taglibs.standard.tag.rt.fmt.BundleTag - JSP - - -Resource bundle base name. This is the bundle's -fully-qualified resource name, which has the same -form as a fully-qualified class name, that is, it uses -"." as the package component separator and does not -have any file type (such as ".class" or ".properties") -suffix. - - basename - true - true - - - -Prefix to be prepended to the value of the message -key of any nested <fmt:message> action. - - prefix - false - true - - - - - - Loads a resource bundle and stores it in the named scoped variable or - the bundle configuration variable - - setBundle - org.apache.taglibs.standard.tag.rt.fmt.SetBundleTag - empty - - -Resource bundle base name. This is the bundle's -fully-qualified resource name, which has the same -form as a fully-qualified class name, that is, it uses -"." as the package component separator and does not -have any file type (such as ".class" or ".properties") -suffix. - - basename - true - true - - - -Name of the exported scoped variable which stores -the i18n localization context of type -javax.servlet.jsp.jstl.fmt.LocalizationC -ontext. - - var - false - false - - - -Scope of var or the localization context -configuration variable. - - scope - false - false - - - - - - Maps key to localized message and performs parametric replacement - - message - org.apache.taglibs.standard.tag.rt.fmt.MessageTag - JSP - - -Message key to be looked up. - - key - false - true - - - -Localization context in whose resource -bundle the message key is looked up. - - bundle - false - true - - - -Name of the exported scoped variable -which stores the localized message. - - var - false - false - - - -Scope of var. - - scope - false - false - - - - - - Supplies an argument for parametric replacement to a containing - <message> tag - - param - org.apache.taglibs.standard.tag.rt.fmt.ParamTag - JSP - - -Argument used for parametric replacement. - - value - false - true - - - - - - Formats a numeric value as a number, currency, or percentage - - formatNumber - org.apache.taglibs.standard.tag.rt.fmt.FormatNumberTag - JSP - - -Numeric value to be formatted. - - value - false - true - - - -Specifies whether the value is to be -formatted as number, currency, or -percentage. - - type - false - true - - - -Custom formatting pattern. - - pattern - false - true - - - -ISO 4217 currency code. Applied only -when formatting currencies (i.e. if type is -equal to "currency"); ignored otherwise. - - currencyCode - false - true - - - -Currency symbol. Applied only when -formatting currencies (i.e. if type is equal -to "currency"); ignored otherwise. - - currencySymbol - false - true - - - -Specifies whether the formatted output -will contain any grouping separators. - - groupingUsed - false - true - - - -Maximum number of digits in the integer -portion of the formatted output. - - maxIntegerDigits - false - true - - - -Minimum number of digits in the integer -portion of the formatted output. - - minIntegerDigits - false - true - - - -Maximum number of digits in the -fractional portion of the formatted output. - - maxFractionDigits - false - true - - - -Minimum number of digits in the -fractional portion of the formatted output. - - minFractionDigits - false - true - - - -Name of the exported scoped variable -which stores the formatted result as a -String. - - var - false - false - - - -Scope of var. - - scope - false - false - - - - - - Parses the string representation of a number, currency, or percentage - - parseNumber - org.apache.taglibs.standard.tag.rt.fmt.ParseNumberTag - JSP - - -String to be parsed. - - value - false - true - - - -Specifies whether the string in the value -attribute should be parsed as a number, -currency, or percentage. - - type - false - true - - - -Custom formatting pattern that determines -how the string in the value attribute is to be -parsed. - - pattern - false - true - - - -Locale whose default formatting pattern (for -numbers, currencies, or percentages, -respectively) is to be used during the parse -operation, or to which the pattern specified -via the pattern attribute (if present) is -applied. - - parseLocale - false - true - - - -Specifies whether just the integer portion of -the given value should be parsed. - - integerOnly - false - true - - - -Name of the exported scoped variable which -stores the parsed result (of type -java.lang.Number). - - var - false - false - - - -Scope of var. - - scope - false - false - - - - - - Formats a date and/or time using the supplied styles and pattern - - formatDate - org.apache.taglibs.standard.tag.rt.fmt.FormatDateTag - empty - - -Date and/or time to be formatted. - - value - true - true - - - -Specifies whether the time, the date, or both -the time and date components of the given -date are to be formatted. - - type - false - true - - - -Predefined formatting style for dates. Follows -the semantics defined in class -java.text.DateFormat. Applied only -when formatting a date or both a date and -time (i.e. if type is missing or is equal to -"date" or "both"); ignored otherwise. - - dateStyle - false - true - - - -Predefined formatting style for times. Follows -the semantics defined in class -java.text.DateFormat. Applied only -when formatting a time or both a date and -time (i.e. if type is equal to "time" or "both"); -ignored otherwise. - - timeStyle - false - true - - - -Custom formatting style for dates and times. - - pattern - false - true - - - -Time zone in which to represent the formatted -time. - - timeZone - false - true - - - -Name of the exported scoped variable which -stores the formatted result as a String. - - var - false - false - - - -Scope of var. - - scope - false - false - - - - - - Parses the string representation of a date and/or time - - parseDate - org.apache.taglibs.standard.tag.rt.fmt.ParseDateTag - JSP - - -Date string to be parsed. - - value - false - true - - - -Specifies whether the date string in the -value attribute is supposed to contain a -time, a date, or both. - - type - false - true - - - -Predefined formatting style for days -which determines how the date -component of the date string is to be -parsed. Applied only when formatting a -date or both a date and time (i.e. if type -is missing or is equal to "date" or "both"); -ignored otherwise. - - dateStyle - false - true - - - -Predefined formatting styles for times -which determines how the time -component in the date string is to be -parsed. Applied only when formatting a -time or both a date and time (i.e. if type -is equal to "time" or "both"); ignored -otherwise. - - timeStyle - false - true - - - -Custom formatting pattern which -determines how the date string is to be -parsed. - - pattern - false - true - - - -Time zone in which to interpret any time -information in the date string. - - timeZone - false - true - - - -Locale whose predefined formatting styles -for dates and times are to be used during -the parse operation, or to which the -pattern specified via the pattern -attribute (if present) is applied. - - parseLocale - false - true - - - -Name of the exported scoped variable in -which the parsing result (of type -java.util.Date) is stored. - - var - false - false - - - -Scope of var. - - scope - false - false - - - - diff --git a/web-app/WEB-INF/tld/grails.tld b/web-app/WEB-INF/tld/grails.tld deleted file mode 100644 index 868ec1f..0000000 --- a/web-app/WEB-INF/tld/grails.tld +++ /dev/null @@ -1,551 +0,0 @@ - - - The Grails (Groovy on Rails) custom tag library - 0.2 - grails - http://grails.codehaus.org/tags - - - - link - org.codehaus.groovy.grails.web.taglib.jsp.JspLinkTag - JSP - - action - false - true - - - controller - false - true - - - id - false - true - - - url - false - true - - - params - false - true - - true - - - form - org.codehaus.groovy.grails.web.taglib.jsp.JspFormTag - JSP - - action - false - true - - - controller - false - true - - - id - false - true - - - url - false - true - - - method - true - true - - true - - - select - org.codehaus.groovy.grails.web.taglib.jsp.JspSelectTag - JSP - - name - true - true - - - value - false - true - - - optionKey - false - true - - - optionValue - false - true - - true - - - datePicker - org.codehaus.groovy.grails.web.taglib.jsp.JspDatePickerTag - empty - - name - true - true - - - value - false - true - - - precision - false - true - - false - - - currencySelect - org.codehaus.groovy.grails.web.taglib.jsp.JspCurrencySelectTag - empty - - name - true - true - - - value - false - true - - true - - - localeSelect - org.codehaus.groovy.grails.web.taglib.jsp.JspLocaleSelectTag - empty - - name - true - true - - - value - false - true - - true - - - timeZoneSelect - org.codehaus.groovy.grails.web.taglib.jsp.JspTimeZoneSelectTag - empty - - name - true - true - - - value - false - true - - true - - - checkBox - org.codehaus.groovy.grails.web.taglib.jsp.JspCheckboxTag - empty - - name - true - true - - - value - true - true - - true - - - hasErrors - org.codehaus.groovy.grails.web.taglib.jsp.JspHasErrorsTag - JSP - - model - false - true - - - bean - false - true - - - field - false - true - - false - - - eachError - org.codehaus.groovy.grails.web.taglib.jsp.JspEachErrorTag - JSP - - model - false - true - - - bean - false - true - - - field - false - true - - false - - - renderErrors - org.codehaus.groovy.grails.web.taglib.jsp.JspEachErrorTag - JSP - - model - false - true - - - bean - false - true - - - field - false - true - - - as - true - true - - false - - - message - org.codehaus.groovy.grails.web.taglib.jsp.JspMessageTag - JSP - - code - false - true - - - error - false - true - - - default - false - true - - false - - - remoteFunction - org.codehaus.groovy.grails.web.taglib.jsp.JspRemoteFunctionTag - empty - - before - false - true - - - after - false - true - - - action - false - true - - - controller - false - true - - - id - false - true - - - url - false - true - - - params - false - true - - - asynchronous - false - true - - - method - false - true - - - update - false - true - - - onSuccess - false - true - - - onFailure - false - true - - - onComplete - false - true - - - onLoading - false - true - - - onLoaded - false - true - - - onInteractive - false - true - - true - - - remoteLink - org.codehaus.groovy.grails.web.taglib.jsp.JspRemoteLinkTag - JSP - - before - false - true - - - after - false - true - - - action - false - true - - - controller - false - true - - - id - false - true - - - url - false - true - - - params - false - true - - - asynchronous - false - true - - - method - false - true - - - update - false - true - - - onSuccess - false - true - - - onFailure - false - true - - - onComplete - false - true - - - onLoading - false - true - - - onLoaded - false - true - - - onInteractive - false - true - - true - - - formRemote - org.codehaus.groovy.grails.web.taglib.jsp.JspFormRemoteTag - JSP - - before - false - true - - - after - false - true - - - action - false - true - - - controller - false - true - - - id - false - true - - - url - false - true - - - params - false - true - - - asynchronous - false - true - - - method - false - true - - - update - false - true - - - onSuccess - false - true - - - onFailure - false - true - - - onComplete - false - true - - - onLoading - false - true - - - onLoaded - false - true - - - onInteractive - false - true - - true - - - invokeTag - org.codehaus.groovy.grails.web.taglib.jsp.JspInvokeGrailsTagLibTag - JSP - - it - java.lang.Object - true - NESTED - - - tagName - true - true - - true - - - diff --git a/web-app/WEB-INF/tld/spring.tld b/web-app/WEB-INF/tld/spring.tld deleted file mode 100644 index 1bc7091..0000000 --- a/web-app/WEB-INF/tld/spring.tld +++ /dev/null @@ -1,311 +0,0 @@ - - - - - - 1.1.1 - - 1.2 - - 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. - - - - 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). - - - - htmlEscape - false - true - - - - 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). - - - - code - false - true - - - - arguments - false - true - - - - text - false - true - - - - var - false - true - - - - scope - false - true - - - - htmlEscape - false - true - - - - 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). - - - - code - false - true - - - - arguments - false - true - - - - text - false - true - - - - var - false - true - - - - scope - false - true - - - - htmlEscape - false - true - - - - 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). - - - - errors - org.springframework.validation.Errors - - - - name - true - true - - - - 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 - java.lang.String - - - - 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). - - - - status - org.springframework.web.servlet.support.BindStatus - - - - path - true - true - - - - ignoreNestedPath - false - true - - - - 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). - - - - value - true - true - - - - var - false - true - - - - scope - false - true - - - - htmlEscape - false - true - - - - - diff --git a/web-app/images/grails.png b/web-app/images/grails.png deleted file mode 100644 index 9cb734d..0000000 Binary files a/web-app/images/grails.png and /dev/null differ