├── public ├── javascripts │ ├── main.js │ └── prism.js ├── images │ ├── external.png │ ├── favicon.png │ ├── favicon0.png │ ├── hello-one.png │ ├── play-stack.png │ ├── hello-custom.png │ ├── header-pattern.png │ ├── play-components.png │ ├── compilation-error.png │ ├── request-response.png │ ├── play-request-response.png │ └── play_icon_reverse.svg └── stylesheets │ ├── prism.css │ └── main.css ├── project ├── build.properties └── plugins.sbt ├── README.md ├── .g8 └── form │ ├── generated-test │ ├── README.md │ └── controllers │ │ └── $model__Camel$ControllerTest.java │ ├── default.properties │ └── app │ ├── views │ └── $model__camel$ │ │ └── form.scala.html │ └── controllers │ ├── $model__Camel$Data.java │ └── $model__Camel$Controller.java ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── .gitignore ├── conf ├── application.conf ├── routes └── logback.xml ├── scripts ├── test-sbt ├── script-helper └── test-gradle ├── NOTICE ├── app ├── controllers │ └── HomeController.java └── views │ ├── commonSidebar.scala.html │ ├── main.scala.html │ ├── index.scala.html │ ├── explore.scala.html │ └── tutorial.scala.html ├── test └── controllers │ └── HomeControllerTest.java ├── .mergify.yml ├── .travis.yml ├── gradlew.bat ├── .github └── settings.yml ├── gradlew └── LICENSE /public/javascripts/main.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version=1.2.8 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | MOVED TO https://github.com/playframework/play-samples 2 | -------------------------------------------------------------------------------- /project/plugins.sbt: -------------------------------------------------------------------------------- 1 | addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.7.0") 2 | -------------------------------------------------------------------------------- /.g8/form/generated-test/README.md: -------------------------------------------------------------------------------- 1 | Temporary file until g8-scaffold will generate "test" directory 2 | -------------------------------------------------------------------------------- /.g8/form/default.properties: -------------------------------------------------------------------------------- 1 | description = Generates a Controller with form handling 2 | model = user 3 | -------------------------------------------------------------------------------- /public/images/external.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/playframework/play-java-hello-world-tutorial/2.7.x/public/images/external.png -------------------------------------------------------------------------------- /public/images/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/playframework/play-java-hello-world-tutorial/2.7.x/public/images/favicon.png -------------------------------------------------------------------------------- /public/images/favicon0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/playframework/play-java-hello-world-tutorial/2.7.x/public/images/favicon0.png -------------------------------------------------------------------------------- /public/images/hello-one.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/playframework/play-java-hello-world-tutorial/2.7.x/public/images/hello-one.png -------------------------------------------------------------------------------- /public/images/play-stack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/playframework/play-java-hello-world-tutorial/2.7.x/public/images/play-stack.png -------------------------------------------------------------------------------- /public/images/hello-custom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/playframework/play-java-hello-world-tutorial/2.7.x/public/images/hello-custom.png -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/playframework/play-java-hello-world-tutorial/2.7.x/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /public/images/header-pattern.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/playframework/play-java-hello-world-tutorial/2.7.x/public/images/header-pattern.png -------------------------------------------------------------------------------- /public/images/play-components.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/playframework/play-java-hello-world-tutorial/2.7.x/public/images/play-components.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | logs 2 | target 3 | build 4 | /.idea 5 | /.idea_modules 6 | /.classpath 7 | /.project 8 | /.settings 9 | /RUNNING_PID 10 | /.gradle -------------------------------------------------------------------------------- /conf/application.conf: -------------------------------------------------------------------------------- 1 | # This is the main configuration file for the application. 2 | # https://www.playframework.com/documentation/latest/ConfigFile 3 | -------------------------------------------------------------------------------- /public/images/compilation-error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/playframework/play-java-hello-world-tutorial/2.7.x/public/images/compilation-error.png -------------------------------------------------------------------------------- /public/images/request-response.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/playframework/play-java-hello-world-tutorial/2.7.x/public/images/request-response.png -------------------------------------------------------------------------------- /public/images/play-request-response.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/playframework/play-java-hello-world-tutorial/2.7.x/public/images/play-request-response.png -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.9-bin.zip 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStorePath=wrapper/dists 5 | zipStoreBase=GRADLE_USER_HOME 6 | -------------------------------------------------------------------------------- /scripts/test-sbt: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | . "$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )/script-helper" 4 | 5 | echo "+----------------------------+" 6 | echo "| Executing tests using sbt |" 7 | echo "+----------------------------+" 8 | sbt ++$TRAVIS_SCALA_VERSION test -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | Written by Lightbend 2 | 3 | To the extent possible under law, the author(s) have dedicated all copyright and 4 | related and neighboring rights to this software to the public domain worldwide. 5 | This software is distributed without any warranty. 6 | 7 | You should have received a copy of the CC0 Public Domain Dedication along with 8 | this software. If not, see . 9 | -------------------------------------------------------------------------------- /scripts/script-helper: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -o pipefail 5 | 6 | java_version=$(java -version 2>&1 | java -version 2>&1 | awk -F '"' '/version/ {print $2}') 7 | 8 | if [[ $java_version = 1.8* ]] ; then 9 | echo "The build is using Java 8 ($java_version). No addional JVM params needed." 10 | else 11 | echo "The build is using Java 9+ ($java_version). We need additional JVM parameters" 12 | export _JAVA_OPTIONS="$_JAVA_OPTIONS --add-modules=java.xml.bind" 13 | fi -------------------------------------------------------------------------------- /.g8/form/app/views/$model__camel$/form.scala.html: -------------------------------------------------------------------------------- 1 | @($model;format="camel"$Form: Form[$model;format="Camel"$Data]) 2 | 3 |

$model;format="camel"$ form

4 | 5 | @flash.getOrDefault("success", "") 6 | 7 | @helper.form(action = routes.$model;format="Camel"$Controller.$model;format="camel"$Post()) { 8 | @helper.CSRF.formField 9 | @helper.inputText($model;format="camel"$Form("name")) 10 | @helper.inputText($model;format="camel"$Form("age")) 11 | 12 | } 13 | -------------------------------------------------------------------------------- /conf/routes: -------------------------------------------------------------------------------- 1 | # Routes 2 | # This file defines all application routes (Higher priority routes first) 3 | # ~~~~ 4 | 5 | # An example controller showing a sample home page 6 | GET / controllers.HomeController.index 7 | GET /explore controllers.HomeController.explore 8 | GET /tutorial controllers.HomeController.tutorial 9 | 10 | 11 | # Map static resources from the /public folder to the /assets URL path 12 | GET /assets/*file controllers.Assets.versioned(path="/public", file: Asset) 13 | -------------------------------------------------------------------------------- /scripts/test-gradle: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | . "$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )/script-helper" 4 | 5 | # Using cut because TRAVIS_SCALA_VERSION is the full Scala 6 | # version (for example 2.12.4), but Gradle expects just the 7 | # binary version (for example 2.12) 8 | scala_binary_version=$(echo $TRAVIS_SCALA_VERSION | cut -c1-4) 9 | 10 | echo "+------------------------------+" 11 | echo "| Executing tests using Gradle |" 12 | echo "+------------------------------+" 13 | ./gradlew -Dscala.binary.version=$scala_binary_version check -i --stacktrace 14 | -------------------------------------------------------------------------------- /public/images/play_icon_reverse.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.g8/form/app/controllers/$model__Camel$Data.java: -------------------------------------------------------------------------------- 1 | package controllers; 2 | 3 | import play.data.validation.Constraints; 4 | 5 | public class $model;format="Camel"$Data { 6 | 7 | @Constraints.Required 8 | private String name; 9 | 10 | @Constraints.Required 11 | private Integer age; 12 | 13 | public $model;format="Camel"$Data() { 14 | } 15 | 16 | public String getName() { 17 | return name; 18 | } 19 | 20 | public void setName(String name) { 21 | this.name = name; 22 | } 23 | 24 | public Integer getAge() { 25 | return age; 26 | } 27 | 28 | public void setAge(Integer age) { 29 | this.age = age; 30 | } 31 | 32 | @Override 33 | public String toString() { 34 | return String.format("$model;format="Camel"$Data(%s, %s)", name, age); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /app/controllers/HomeController.java: -------------------------------------------------------------------------------- 1 | package controllers; 2 | 3 | import play.mvc.*; 4 | 5 | /** 6 | * This controller contains an action to handle HTTP requests 7 | * to the application's home page. 8 | */ 9 | public class HomeController extends Controller { 10 | 11 | /** 12 | * An action that renders an HTML page with a welcome message. 13 | * The configuration in the routes file means that 14 | * this method will be called when the application receives a 15 | * GET request with a path of /. 16 | */ 17 | public Result index() { 18 | return ok(views.html.index.render()); 19 | } 20 | 21 | public Result explore() { 22 | return ok(views.html.explore.render()); 23 | } 24 | 25 | public Result tutorial() { 26 | return ok(views.html.tutorial.render()); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /app/views/commonSidebar.scala.html: -------------------------------------------------------------------------------- 1 | @() 2 | @defining(play.core.PlayVersion.current) { version => 3 |

Table of Contents

4 | 9 |

Related Resources

10 | 17 | } -------------------------------------------------------------------------------- /test/controllers/HomeControllerTest.java: -------------------------------------------------------------------------------- 1 | package controllers; 2 | 3 | import org.junit.Test; 4 | import play.Application; 5 | import play.inject.guice.GuiceApplicationBuilder; 6 | import play.mvc.Http; 7 | import play.mvc.Result; 8 | import play.test.WithApplication; 9 | 10 | import static org.junit.Assert.assertEquals; 11 | import static play.mvc.Http.Status.OK; 12 | import static play.test.Helpers.GET; 13 | import static play.test.Helpers.route; 14 | 15 | public class HomeControllerTest extends WithApplication { 16 | 17 | @Override 18 | protected Application provideApplication() { 19 | return new GuiceApplicationBuilder().build(); 20 | } 21 | 22 | @Test 23 | public void testIndex() { 24 | Http.RequestBuilder request = new Http.RequestBuilder() 25 | .method(GET) 26 | .uri("/"); 27 | 28 | Result result = route(app, request); 29 | assertEquals(OK, result.status()); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /.mergify.yml: -------------------------------------------------------------------------------- 1 | pull_request_rules: 2 | - name: Merge PRs that are ready 3 | conditions: 4 | - status-success=Travis CI - Pull Request 5 | - status-success=typesafe-cla-validator 6 | - "#approved-reviews-by>=1" 7 | - "#review-requested=0" 8 | - "#changes-requested-reviews-by=0" 9 | - label!=status:block-merge 10 | actions: 11 | merge: 12 | method: squash 13 | strict: smart 14 | 15 | - name: Merge TemplateControl's PRs that are ready 16 | conditions: 17 | - status-success=Travis CI - Pull Request 18 | - "#review-requested=0" 19 | - "#changes-requested-reviews-by=0" 20 | - label!=status:block-merge 21 | - label=status:merge-when-green 22 | - label!=status:block-merge 23 | actions: 24 | merge: 25 | method: squash 26 | strict: smart 27 | 28 | - name: Delete the PR branch after merge 29 | conditions: 30 | - merged 31 | actions: 32 | delete_head_branch: {} 33 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: scala 2 | scala: 2.12.8 3 | script: $SCRIPT 4 | 5 | env: 6 | matrix: 7 | - SCRIPT=scripts/test-sbt TRAVIS_JDK=adopt@1.8.202-08 8 | - SCRIPT=scripts/test-sbt TRAVIS_JDK=adopt@1.11.0-2 9 | - SCRIPT=scripts/test-gradle TRAVIS_JDK=adopt@1.8.202-08 10 | - SCRIPT=scripts/test-gradle TRAVIS_JDK=adopt@1.11.0-2 11 | 12 | matrix: 13 | fast_finish: true 14 | allow_failures: 15 | - env: SCRIPT=scripts/test-gradle TRAVIS_JDK=adopt@1.8.202-08 # current gradle doesn't support play 2.7 16 | - env: SCRIPT=scripts/test-gradle TRAVIS_JDK=adopt@1.11.0-2 # current gradle doesn't support play 2.7 17 | - env: SCRIPT=scripts/test-sbt TRAVIS_JDK=adopt@1.11.0-2 # not fully supported but allows problem discovery 18 | 19 | before_install: curl -Ls https://git.io/jabba | bash && . ~/.jabba/jabba.sh 20 | install: jabba install "$TRAVIS_JDK" && jabba use "$_" && java -Xmx32m -version 21 | 22 | cache: 23 | directories: 24 | - "$HOME/.gradle/caches" 25 | - "$HOME/.ivy2/cache" 26 | - "$HOME/.jabba/jdk" 27 | - "$HOME/.sbt" 28 | 29 | before_cache: 30 | - find $HOME/.ivy2 -name "ivydata-*.properties" -delete 31 | - find $HOME/.sbt -name "*.lock" -delete 32 | -------------------------------------------------------------------------------- /conf/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | ${application.home:-.}/logs/application.log 8 | 9 | %date [%level] from %logger in %thread - %message%n%xException 10 | 11 | 12 | 13 | 14 | 15 | %coloredLevel %logger{15} - %message%n%xException{10} 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /app/views/main.scala.html: -------------------------------------------------------------------------------- 1 | @* 2 | * This template is called from the `index` template. This template 3 | * handles the rendering of the page header and body tags. It takes 4 | * two arguments, a `String` for the title of the page and an `Html` 5 | * object to insert into the body of the page. 6 | *@ 7 | @(title: String)(content: Html) 8 | 9 | 10 | 11 | 12 | 13 | @title 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 |
25 | logo 26 |

Play Hello World Web Tutorial

27 |
28 |
29 | @content 30 | 31 | 32 | -------------------------------------------------------------------------------- /.g8/form/generated-test/controllers/$model__Camel$ControllerTest.java: -------------------------------------------------------------------------------- 1 | package controllers; 2 | 3 | import org.junit.Test; 4 | import play.Application; 5 | import play.filters.csrf.*; 6 | import play.inject.guice.GuiceApplicationBuilder; 7 | import play.mvc.*; 8 | import play.test.WithApplication; 9 | 10 | import java.util.HashMap; 11 | 12 | import static org.junit.Assert.assertEquals; 13 | import static play.mvc.Http.RequestBuilder; 14 | import static play.mvc.Http.Status.OK; 15 | import static play.test.Helpers.*; 16 | import static play.api.test.CSRFTokenHelper.*; 17 | 18 | public class $model;format="Camel"$ControllerTest extends WithApplication { 19 | 20 | @Override 21 | protected Application provideApplication() { 22 | return new GuiceApplicationBuilder().build(); 23 | } 24 | 25 | @Test 26 | public void test$model;format="Camel"$Get() { 27 | RequestBuilder request = new RequestBuilder() 28 | .method(GET) 29 | .uri("/$model;format="camel"$"); 30 | 31 | Result result = route(app, request); 32 | assertEquals(OK, result.status()); 33 | } 34 | 35 | @Test 36 | public void test$model;format="Camel"$Post() { 37 | HashMap formData = new HashMap<>(); 38 | formData.put("name", "play"); 39 | formData.put("age", "4"); 40 | RequestBuilder request = addCSRFToken(new RequestBuilder() 41 | .header(Http.HeaderNames.HOST, "localhost") 42 | .method(POST) 43 | .bodyForm(formData) 44 | .uri("/$model;format="camel"$")); 45 | 46 | Result result = route(app, request); 47 | assertEquals(SEE_OTHER, result.status()); 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /.g8/form/app/controllers/$model__Camel$Controller.java: -------------------------------------------------------------------------------- 1 | package controllers; 2 | 3 | import play.data.Form; 4 | import play.data.FormFactory; 5 | import play.mvc.Controller; 6 | import play.mvc.Result; 7 | 8 | import javax.inject.Inject; 9 | 10 | // Add the following to conf/routes 11 | /* 12 | GET /$model;format="camel"$ controllers.$model;format="Camel"$Controller.$model;format="camel"$Get 13 | POST /$model;format="camel"$ controllers.$model;format="Camel"$Controller.$model;format="camel"$Post 14 | */ 15 | 16 | /** 17 | * $model;format="Camel"$ form controller for Play Java 18 | */ 19 | public class $model;format="Camel"$Controller extends Controller { 20 | 21 | private final Form<$model;format="Camel"$Data> $model;format="camel"$Form; 22 | 23 | @Inject 24 | public $model;format="Camel"$Controller(FormFactory formFactory) { 25 | this.$model;format="camel"$Form = formFactory.form($model;format="Camel"$Data.class); 26 | } 27 | 28 | public Result $model;format="camel"$Get() { 29 | return ok(views.html.$model;format="camel"$.form.render($model;format="camel"$Form)); 30 | } 31 | 32 | public Result $model;format="camel"$Post() { 33 | Form<$model;format="Camel"$Data> boundForm = $model;format="camel"$Form.bindFromRequest(); 34 | if (boundForm.hasErrors()) { 35 | return badRequest(views.html.$model;format="camel"$.form.render(boundForm)); 36 | } else { 37 | $model;format="Camel"$Data $model;format="camel"$ = boundForm.get(); 38 | flash("success", "$model;format="Camel"$ " + $model;format="camel"$); 39 | return redirect(routes.$model;format="Camel"$Controller.$model;format="camel"$Get()); 40 | } 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /.github/settings.yml: -------------------------------------------------------------------------------- 1 | # These settings are synced to GitHub by https://probot.github.io/apps/settings/ 2 | repository: 3 | homepage: "https://developer.lightbend.com/start/?group=play" 4 | topics: playframework, example, example-project, sample, sample-app, jvm, webapp 5 | private: false 6 | has_issues: true 7 | # We don't need projects in sample projects 8 | has_projects: false 9 | # We don't need wiki in sample projects 10 | has_wiki: false 11 | has_downloads: true 12 | default_branch: 2.7.x 13 | allow_squash_merge: true 14 | allow_merge_commit: false 15 | allow_rebase_merge: false 16 | 17 | teams: 18 | - name: core 19 | permission: admin 20 | - name: integrators 21 | permission: write 22 | - name: write-bots 23 | permission: write 24 | 25 | branches: 26 | - name: "[0-9].*.x" 27 | protection: 28 | # We don't require reviews for sample applications because they are mainly 29 | # updated by template-control, which is an automated process 30 | required_pull_request_reviews: null 31 | # Required. Require status checks to pass before merging. Set to null to disable 32 | required_status_checks: 33 | # Required. The list of status checks to require in order to merge into this branch 34 | contexts: ["Travis CI - Pull Request", "typesafe-cla-validator"] 35 | 36 | # Labels: tailored list of labels to be used by sample applications 37 | labels: 38 | - color: f9d0c4 39 | name: "closed:declined" 40 | - color: f9d0c4 41 | name: "closed:duplicated" 42 | oldname: duplicate 43 | - color: f9d0c4 44 | name: "closed:invalid" 45 | oldname: invalid 46 | - color: f9d0c4 47 | name: "closed:question" 48 | oldname: question 49 | - color: f9d0c4 50 | name: "closed:wontfix" 51 | oldname: wontfix 52 | - color: 7057ff 53 | name: "good first issue" 54 | - color: 7057ff 55 | name: "Hacktoberfest" 56 | - color: 7057ff 57 | name: "help wanted" 58 | - color: cceecc 59 | name: "status:backlog" 60 | oldname: backlog 61 | - color: b60205 62 | name: "status:block-merge" 63 | oldname: block-merge 64 | - color: b60205 65 | name: "status:blocked" 66 | - color: 0e8a16 67 | name: "status:in-progress" 68 | - color: 0e8a16 69 | name: "status:merge-when-green" 70 | oldname: merge-when-green 71 | - color: fbca04 72 | name: "status:needs-backport" 73 | - color: fbca04 74 | name: "status:needs-forwardport" 75 | - color: fbca04 76 | name: "status:needs-info" 77 | - color: fbca04 78 | name: "status:needs-verification" 79 | - color: 0e8a16 80 | name: "status:ready" 81 | - color: fbca04 82 | name: "status:to-review" 83 | oldname: review 84 | - color: c5def5 85 | name: "topic:build/tests" 86 | - color: c5def5 87 | name: "topic:dev-environment" 88 | - color: c5def5 89 | name: "topic:documentation" 90 | - color: c5def5 91 | name: "topic:jdk-next" 92 | - color: b60205 93 | name: "type:defect" 94 | oldname: bug 95 | - color: 0052cc 96 | name: "type:feature" 97 | - color: 0052cc 98 | name: "type:improvement" 99 | oldname: enhancement 100 | - color: 0052cc 101 | name: "type:updates" 102 | - color: bf0d92 103 | name: "type:template-control" 104 | oldname: template-control 105 | -------------------------------------------------------------------------------- /app/views/index.scala.html: -------------------------------------------------------------------------------- 1 | @() 2 | 3 | 4 | @main("Welcome") { 5 | @defining(play.core.PlayVersion.current) { version => 6 | 7 |
8 |
9 |
10 |

Welcome to the Hello World Tutorial!

11 |

This tutorial introduces Play Framework, describes how Play web applications work, and walks you through steps 12 | to create page that displays a Hello World greeting.

13 |

If you loaded this page from the web server running on localhost:9000, congratulations! You have 14 | successfully built and run a Play application. If not, you likely opened the source index.scala.html 15 | file. Please follow the directions in the README.md file in the top-level project directory to run 16 | the tutorial.

17 | 18 |

Introduction to Play

19 |

As illustrated below, Play is a full-stack framework with all of the components you need to build a Web 20 | Application or a REST service, including:

21 |
    22 |
  • An integrated HTTP server
  • 23 |
  • Form handling
  • 24 |
  • Cross-Site Request Forgery (CSRF) protection
  • 25 |
  • A powerful routing mechanism
  • 26 |
  • I18n support, and more.
  • 27 |
28 | 29 | Play Stack 30 | 31 |

Play integrates with many object relational mapping (ORM) layers. It has out-of-the-box support for Anorm, JavaEbean, 33 | PlaySlick, and 34 | JPA. See Accessing an SQL Database for more information. Many customers use NoSQL, other ORMs or 36 | even access data from a REST service.

37 | 38 | 39 |

Play APIs are available in both Java and Scala. The Framework uses Akka 40 | and Akka HTTP under the 41 | hood. This endows Play applications with a stateless, non-blocking, event-driven architecture that provides 42 | horizontal and vertical scalability and uses resources more efficiently. Play projects contain Scala 43 | components, but because Play has a Java API, Java developers do not need to learn Scala to use Play 44 | successfully.

45 | 46 |

Here are just a few of the reasons developers love using Play Framework:

47 |
    48 |
  • Its Model-View-Controller (MVC) architecture is familiar and easy to learn.
  • 49 |
  • Direct support of common web development tasks and hot reloading saves precious development time.
  • 50 |
  • A large active community promotes knowledge sharing.
  • 51 |
  • Use of Twirl templates to render pages. The Twirl 52 | template language is: 53 |
      54 |
    1. Easy to learn
    2. 55 |
    3. Requires no special editor
    4. 56 |
    5. Provides type safety
    6. 57 |
    7. Is compiled so that errors display in the browser
    8. 58 |
    59 |
  • 60 |
61 | 62 |

To learn more about Play's benefits, visit the Play 63 | website.

64 | 65 |

Next steps

66 |

Now, let's explore the tutorial Play application.

67 |
68 | 71 |
72 |
73 | } 74 | } -------------------------------------------------------------------------------- /public/stylesheets/prism.css: -------------------------------------------------------------------------------- 1 | /* PrismJS 1.15.0 2 | https://prismjs.com/download.html#themes=prism&languages=clike+java+scala&plugins=line-numbers */ 3 | /** 4 | * prism.js default theme for JavaScript, CSS and HTML 5 | * Based on dabblet (http://dabblet.com) 6 | * @author Lea Verou 7 | */ 8 | 9 | code[class*="language-"], 10 | pre[class*="language-"] { 11 | color: black; 12 | background: none; 13 | text-shadow: 0 1px white; 14 | font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; 15 | text-align: left; 16 | white-space: pre; 17 | word-spacing: normal; 18 | word-break: normal; 19 | word-wrap: normal; 20 | line-height: 1.5; 21 | 22 | -moz-tab-size: 4; 23 | -o-tab-size: 4; 24 | tab-size: 4; 25 | 26 | -webkit-hyphens: none; 27 | -moz-hyphens: none; 28 | -ms-hyphens: none; 29 | hyphens: none; 30 | } 31 | 32 | pre[class*="language-"]::-moz-selection, pre[class*="language-"] ::-moz-selection, 33 | code[class*="language-"]::-moz-selection, code[class*="language-"] ::-moz-selection { 34 | text-shadow: none; 35 | background: #b3d4fc; 36 | } 37 | 38 | pre[class*="language-"]::selection, pre[class*="language-"] ::selection, 39 | code[class*="language-"]::selection, code[class*="language-"] ::selection { 40 | text-shadow: none; 41 | background: #b3d4fc; 42 | } 43 | 44 | @media print { 45 | code[class*="language-"], 46 | pre[class*="language-"] { 47 | text-shadow: none; 48 | } 49 | } 50 | 51 | /* Code blocks */ 52 | pre[class*="language-"] { 53 | padding: 1em; 54 | margin: .5em 0; 55 | overflow: auto; 56 | } 57 | 58 | :not(pre) > code[class*="language-"], 59 | pre[class*="language-"] { 60 | background: #f5f2f0; 61 | } 62 | 63 | /* Inline code */ 64 | :not(pre) > code[class*="language-"] { 65 | padding: .1em; 66 | border-radius: .3em; 67 | white-space: normal; 68 | } 69 | 70 | .token.comment, 71 | .token.prolog, 72 | .token.doctype, 73 | .token.cdata { 74 | color: slategray; 75 | } 76 | 77 | .token.punctuation { 78 | color: #999; 79 | } 80 | 81 | .namespace { 82 | opacity: .7; 83 | } 84 | 85 | .token.property, 86 | .token.tag, 87 | .token.boolean, 88 | .token.number, 89 | .token.constant, 90 | .token.symbol, 91 | .token.deleted { 92 | color: #905; 93 | } 94 | 95 | .token.selector, 96 | .token.attr-name, 97 | .token.string, 98 | .token.char, 99 | .token.builtin, 100 | .token.inserted { 101 | color: #690; 102 | } 103 | 104 | .token.operator, 105 | .token.entity, 106 | .token.url, 107 | .language-css .token.string, 108 | .style .token.string { 109 | color: #9a6e3a; 110 | background: hsla(0, 0%, 100%, .5); 111 | } 112 | 113 | .token.atrule, 114 | .token.attr-value, 115 | .token.keyword { 116 | color: #07a; 117 | } 118 | 119 | .token.function, 120 | .token.class-name { 121 | color: #DD4A68; 122 | } 123 | 124 | .token.regex, 125 | .token.important, 126 | .token.variable { 127 | color: #e90; 128 | } 129 | 130 | .token.important, 131 | .token.bold { 132 | font-weight: bold; 133 | } 134 | .token.italic { 135 | font-style: italic; 136 | } 137 | 138 | .token.entity { 139 | cursor: help; 140 | } 141 | 142 | pre[class*="language-"].line-numbers { 143 | position: relative; 144 | padding-left: 3.8em; 145 | counter-reset: linenumber; 146 | } 147 | 148 | pre[class*="language-"].line-numbers > code { 149 | position: relative; 150 | white-space: inherit; 151 | } 152 | 153 | .line-numbers .line-numbers-rows { 154 | position: absolute; 155 | pointer-events: none; 156 | top: 0; 157 | font-size: 100%; 158 | left: -3.8em; 159 | width: 3em; /* works for line-numbers below 1000 lines */ 160 | letter-spacing: -1px; 161 | border-right: 1px solid #999; 162 | 163 | -webkit-user-select: none; 164 | -moz-user-select: none; 165 | -ms-user-select: none; 166 | user-select: none; 167 | 168 | } 169 | 170 | .line-numbers-rows > span { 171 | pointer-events: none; 172 | display: block; 173 | counter-increment: linenumber; 174 | } 175 | 176 | .line-numbers-rows > span:before { 177 | content: counter(linenumber); 178 | color: #999; 179 | display: block; 180 | padding-right: 0.8em; 181 | text-align: right; 182 | } 183 | 184 | -------------------------------------------------------------------------------- /app/views/explore.scala.html: -------------------------------------------------------------------------------- 1 | @() 2 | 3 | @main("Hello World") { 4 | @defining(play.core.PlayVersion.current) { version => 5 | 6 |
7 |
8 |
9 |

Play application overview

10 | 11 |

This tutorial is implemented as a Play application that demonstrates Play's basics. We started with the Play 12 | Java seed template, which set up the application project structure and the configuration to build with either 13 | Gradle or sbt. We removed the Gradle files for simplicity and added stylesheets with Play's colors and a Table 14 | of Contents.

15 |

Let's start by looking at what happens at runtime. When you entered the server name and port number, http://localhost:9000/, in your browser:

17 |
    18 |
  • The browser requested the root / URI from the HTTP server using the GET method.
  • 19 |
  • The Play internal HTTP Server received the request.
  • 20 |
  • Play resolved the request using the routes file, which maps URIs to controller action methods.
  • 21 |
  • The action method used Twirl templates to render the index page.
  • 22 |
  • The HTTP server returned the response as an HTML page.
  • 23 |
24 |

At a high level, the flow looks something like this:

25 |

Request and response

26 |

Explore the project

27 |

Next, let's look at the tutorial project to locate the implementation for the following:

28 |
    29 |
  • The controller action method that defines how to handle a request to the root URI.
  • 30 |
  • The conf/routes file that maps the request to the controller method.
  • 31 |
  • The Twirl template that the action method calls to render the HTML markup.
  • 32 |
33 |

Using a command window or a GUI, start with the top-level project directory. The following directories contain 34 | application components:

35 | 36 |
Note: When changing directories in Windows shells, substitute / for \ in 37 | path names.
38 |

39 |

    40 |
  1. The app subdirectory is where you put your Java code and packages. It contains directories 41 | for controllers and views, which will be familiar to those experienced with the 42 | Model View Controller (MVC) architecture. Since this simple project does not need an external data 43 | repository, it does not contain a models directory, but this is where you would add it. You 44 | could also add a service package and utils here.
  2. 45 |
  3. The public subdirectory contains directories for images, javascripts, 46 | and stylesheets.
  4. 47 |
  5. The conf directory contains application configuration. For a more detailed explanation of 48 | the project's structure, see Play Application Layout.
  6. 50 | 51 |
  7. 52 |

    To locate the controller action method, open app/controllers/HomeController.java file with 53 | your favorite text editor.

    54 | 55 |

    The Homecontroller class includes the index action method, as shown below. 56 | This is a very simple action method that generate an HTML page from the index.scala.html 57 | Twirl template file.

    58 |
    public Result index() {
    59 |   return ok(views.html.index.render());
    60 | }
    61 |
  8. 62 |
  9. To view the route that maps the browser request to the controller method, open the conf/routes 63 | file. 64 |

    A route consists of an HTTP method, a path, and an action. This control over the URL schema makes it 65 | easy to 66 | design clean, human-readable, bookmarkable URLs. The following line maps a GET request for the root URL 67 | / 68 | to the index action in HomeController:

    69 | GET / controllers.HomeController.index
  10. 70 |
  11. Open app/views/index.scala.html with your text editor. 71 |

    The main directive in this file calls the main template main.scala.html with the string 72 | "Welcome" 73 | to generate the page. 74 | You can open app/views/main.scala.html to see how a String parameter sets the 75 | page 76 | title.

    77 |
  12. 78 |
79 |

80 |

Next steps

81 |

With this overview of the tutorial application, you are ready to add 82 | your own "Hello World" greeting.

83 |
84 | 87 |
88 |
89 | 90 | } 91 | } -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | CC0 1.0 Universal 2 | 3 | Statement of Purpose 4 | 5 | The laws of most jurisdictions throughout the world automatically confer 6 | exclusive Copyright and Related Rights (defined below) upon the creator and 7 | subsequent owner(s) (each and all, an "owner") of an original work of 8 | authorship and/or a database (each, a "Work"). 9 | 10 | Certain owners wish to permanently relinquish those rights to a Work for the 11 | purpose of contributing to a commons of creative, cultural and scientific 12 | works ("Commons") that the public can reliably and without fear of later 13 | claims of infringement build upon, modify, incorporate in other works, reuse 14 | and redistribute as freely as possible in any form whatsoever and for any 15 | purposes, including without limitation commercial purposes. These owners may 16 | contribute to the Commons to promote the ideal of a free culture and the 17 | further production of creative, cultural and scientific works, or to gain 18 | reputation or greater distribution for their Work in part through the use and 19 | efforts of others. 20 | 21 | For these and/or other purposes and motivations, and without any expectation 22 | of additional consideration or compensation, the person associating CC0 with a 23 | Work (the "Affirmer"), to the extent that he or she is an owner of Copyright 24 | and Related Rights in the Work, voluntarily elects to apply CC0 to the Work 25 | and publicly distribute the Work under its terms, with knowledge of his or her 26 | Copyright and Related Rights in the Work and the meaning and intended legal 27 | effect of CC0 on those rights. 28 | 29 | 1. Copyright and Related Rights. A Work made available under CC0 may be 30 | protected by copyright and related or neighboring rights ("Copyright and 31 | Related Rights"). Copyright and Related Rights include, but are not limited 32 | to, the following: 33 | 34 | i. the right to reproduce, adapt, distribute, perform, display, communicate, 35 | and translate a Work; 36 | 37 | ii. moral rights retained by the original author(s) and/or performer(s); 38 | 39 | iii. publicity and privacy rights pertaining to a person's image or likeness 40 | depicted in a Work; 41 | 42 | iv. rights protecting against unfair competition in regards to a Work, 43 | subject to the limitations in paragraph 4(a), below; 44 | 45 | v. rights protecting the extraction, dissemination, use and reuse of data in 46 | a Work; 47 | 48 | vi. database rights (such as those arising under Directive 96/9/EC of the 49 | European Parliament and of the Council of 11 March 1996 on the legal 50 | protection of databases, and under any national implementation thereof, 51 | including any amended or successor version of such directive); and 52 | 53 | vii. other similar, equivalent or corresponding rights throughout the world 54 | based on applicable law or treaty, and any national implementations thereof. 55 | 56 | 2. Waiver. To the greatest extent permitted by, but not in contravention of, 57 | applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and 58 | unconditionally waives, abandons, and surrenders all of Affirmer's Copyright 59 | and Related Rights and associated claims and causes of action, whether now 60 | known or unknown (including existing as well as future claims and causes of 61 | action), in the Work (i) in all territories worldwide, (ii) for the maximum 62 | duration provided by applicable law or treaty (including future time 63 | extensions), (iii) in any current or future medium and for any number of 64 | copies, and (iv) for any purpose whatsoever, including without limitation 65 | commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes 66 | the Waiver for the benefit of each member of the public at large and to the 67 | detriment of Affirmer's heirs and successors, fully intending that such Waiver 68 | shall not be subject to revocation, rescission, cancellation, termination, or 69 | any other legal or equitable action to disrupt the quiet enjoyment of the Work 70 | by the public as contemplated by Affirmer's express Statement of Purpose. 71 | 72 | 3. Public License Fallback. Should any part of the Waiver for any reason be 73 | judged legally invalid or ineffective under applicable law, then the Waiver 74 | shall be preserved to the maximum extent permitted taking into account 75 | Affirmer's express Statement of Purpose. In addition, to the extent the Waiver 76 | is so judged Affirmer hereby grants to each affected person a royalty-free, 77 | non transferable, non sublicensable, non exclusive, irrevocable and 78 | unconditional license to exercise Affirmer's Copyright and Related Rights in 79 | the Work (i) in all territories worldwide, (ii) for the maximum duration 80 | provided by applicable law or treaty (including future time extensions), (iii) 81 | in any current or future medium and for any number of copies, and (iv) for any 82 | purpose whatsoever, including without limitation commercial, advertising or 83 | promotional purposes (the "License"). The License shall be deemed effective as 84 | of the date CC0 was applied by Affirmer to the Work. Should any part of the 85 | License for any reason be judged legally invalid or ineffective under 86 | applicable law, such partial invalidity or ineffectiveness shall not 87 | invalidate the remainder of the License, and in such case Affirmer hereby 88 | affirms that he or she will not (i) exercise any of his or her remaining 89 | Copyright and Related Rights in the Work or (ii) assert any associated claims 90 | and causes of action with respect to the Work, in either case contrary to 91 | Affirmer's express Statement of Purpose. 92 | 93 | 4. Limitations and Disclaimers. 94 | 95 | a. No trademark or patent rights held by Affirmer are waived, abandoned, 96 | surrendered, licensed or otherwise affected by this document. 97 | 98 | b. Affirmer offers the Work as-is and makes no representations or warranties 99 | of any kind concerning the Work, express, implied, statutory or otherwise, 100 | including without limitation warranties of title, merchantability, fitness 101 | for a particular purpose, non infringement, or the absence of latent or 102 | other defects, accuracy, or the present or absence of errors, whether or not 103 | discoverable, all to the greatest extent permissible under applicable law. 104 | 105 | c. Affirmer disclaims responsibility for clearing rights of other persons 106 | that may apply to the Work or any use thereof, including without limitation 107 | any person's Copyright and Related Rights in the Work. Further, Affirmer 108 | disclaims responsibility for obtaining any necessary consents, permissions 109 | or other rights required for any use of the Work. 110 | 111 | d. Affirmer understands and acknowledges that Creative Commons is not a 112 | party to this document and has no duty or obligation with respect to this 113 | CC0 or use of the Work. 114 | 115 | For more information, please see 116 | 117 | -------------------------------------------------------------------------------- /app/views/tutorial.scala.html: -------------------------------------------------------------------------------- 1 | @() 2 | 3 | @main("Hello World") { 4 | @defining(play.core.PlayVersion.current) { version => 5 | 6 |
7 |
8 |
9 |

Implementing Hello World

10 |

This tutorial provides the instructions for using sbt 11 | (simple build tool) from a command window to build the application, but you can also integrate Play projects 12 | with your favorite IDE.

13 |

To see how simple it is to work with Play, let's add a customized "Hello World" greeting to this tutorial 14 | app. The main steps include:

15 | 21 | 22 |

Create the Hello World page

23 |

Follow these instructions to add a new page:

24 |
    25 |
  1. With any text editor, create a file named hello.scala.html and save it in the app/views 26 | directory of this tutorial project.
  2. 27 |
  3. Add the following contents to the file: 28 |
    @main("Hello") {
     29 |   <section id="content">
     30 |     <div class="wrapper doc">
     31 |       <article>
     32 |         <h1>Hello World</h1>
     33 |       </article>  
     34 |       <aside>
     35 |         @commonSidebar()
     36 |       </aside>
     37 |     </div>
     38 |   </section>
     39 | }
    40 |

    The Twirl and HTML markup for your new page accomplishes the following:

    41 |
      42 |
    • The @ sign tells the template engine to interpret what follows. 43 |

      In this case, @main("Hello") calls the main template, main.scala.html 44 | and passes it the page title of Hello.

      45 |
    • 46 |
    • The content section contains the Hello World greeting. The main template will 47 | insert this into the body of the page.
    • 48 |
    • The <aside> section adds the TOC to the right side so that you will be able to 49 | navigate back to this page. 50 |
    51 |
52 |

Add an action method

53 |

Next, add an action method that will render the new page. To keep things simple, you will add the new 54 | controller to the existing class. In a real application, you can organize controllers in multiple classes if 55 | you wish.

56 |

Open the app/controllers/HomeController.java file. Below the tutorial method and above the 57 | closing brace, add the following method: 58 |

public Result hello() {
 59 |   return ok(views.html.hello.render());      
 60 | }
61 |

62 |

This method has no input parameters and simply renders the new hello page.

63 | 64 |

Define a route

65 | 66 |

A route tells Play how to handle incoming requests and includes the request path, an HTTP 67 | method, and the controller action to invoke. When you add a route to the routes file, Play's 68 | routes compiler will automatically generate a router class that calls that action using an instance of that 69 | controller. For more information see HTTP Routing. By default, the controller instances are created using dependency 71 | injection. See Dependency Injection for more information.

73 |

To define a route for the new page:

74 |
    75 |
  1. Open the conf/routes file.
  2. 76 |
  3. Below the tutorial page route, add the following line: 77 |

    GET /hello controllers.HomeController.hello

    78 |
  4. 79 |
80 |

Test the new page:

81 |
    82 |
  1. If you stopped the application for some reason, restart it with the sbt run command.
  2. 83 |
  3. Enter the URL http://localhost:9000/hello to view the results 84 | of your work. The browser should respond with something like the following: 85 |

    Add Request and response screen

    86 |
  4. 87 |
88 | 89 |

Customize the greeting

90 | 91 |

As the final part of this tutorial, we'll modify the hello page to accept an HTTP request parameter that 92 | passes in a name. The steps include a deliberate mistake to demonstrate how Play provides useful feedback.

93 |

To customize the Hello World greeting, follow these steps:

94 |
    95 |
  1. In the app/controllers/HomeController.java file, modify the hello action 96 | method to accept a String name parameter. The modified action should look like the 97 | following: 98 |
    public Result hello(String name) {
     99 |   return ok(views.html.hello.render());
    100 | }
    101 |
  2. 102 |
  3. In the conf/routes file, add a (name: String) parameter at the end of the 103 | /hello route: 104 |

    GET /hello controllers.HomeController.hello(name: String)

    105 |
  4. 106 |
  5. In Twirl templates, all variables and their types must be declared. From the app/views/ 107 | directory, open the hello.scala.html file and do the following: 108 |
      109 |
    • Insert a new line at the top of the file.
    • 110 |
    • On that line, add an @ directive that declares the name parameter and its type: 111 | @(name: String).
    • 112 |
    • To use the variable on the page, change the text in the <h2> heading from Hello World 113 | to <h2>Hello @name!</h2>. 114 |
    • 115 |
    116 |

    To test the cusomization:

    117 |
      118 |
    1. Open a new browser tab
    2. 119 |
    3. Enter the following URL and pass in any name as a query parameter to the hello method: http://localhost:9000/hello?name=MyName. 121 |

      Play responds with a helpful compilation error that tells you the file and line number causing the 122 | problem. The message shows that the render method in the return value requires a typed parameter: 123 |

      124 |

      Error message

      125 |
    4. 126 |
    127 |
  6. 128 |

    To fix the compilation error, modify the hello action method in HomeController 129 | so that the it includes the name parameter when rendering the view:

    130 |
    public Result hello(String name) {
    131 |   return ok(javaguide.hello.html.helloName.render(name));
    132 | }
    133 |
  7. 134 |
  8. 135 |

    Save the file and refresh the browser. Play detects the change, automatically recompiles, and reloads 136 | the page. The page should display a customized greeting similar to the following:

    137 |

    Hello Malitha

    138 |
  9. 139 |
140 | 141 |

Summary

142 |

Thanks for trying our tutorial. You learned how to use an action method, routes, Twirl template, and 143 | input parameter to create a customized Hello World greeting! You experienced how template compilation 144 | makes it easier to identify and fix problems and how auto-reloading saves time. 145 |

146 |

Next steps

147 |

To learn more about Play, check out these resources:

148 | 156 |
157 | 160 |
161 |
162 | } 163 | } -------------------------------------------------------------------------------- /public/javascripts/prism.js: -------------------------------------------------------------------------------- 1 | /* PrismJS 1.15.0 2 | https://prismjs.com/download.html#themes=prism&languages=clike+java+scala&plugins=line-numbers */ 3 | var _self="undefined"!=typeof window?window:"undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?self:{},Prism=function(){var e=/\blang(?:uage)?-([\w-]+)\b/i,t=0,n=_self.Prism={manual:_self.Prism&&_self.Prism.manual,disableWorkerMessageHandler:_self.Prism&&_self.Prism.disableWorkerMessageHandler,util:{encode:function(e){return e instanceof r?new r(e.type,n.util.encode(e.content),e.alias):"Array"===n.util.type(e)?e.map(n.util.encode):e.replace(/&/g,"&").replace(/e.length)return;if(!(w instanceof s)){if(m&&b!=t.length-1){h.lastIndex=k;var _=h.exec(e);if(!_)break;for(var j=_.index+(d?_[1].length:0),P=_.index+_[0].length,A=b,x=k,O=t.length;O>A&&(P>x||!t[A].type&&!t[A-1].greedy);++A)x+=t[A].length,j>=x&&(++b,k=x);if(t[b]instanceof s)continue;I=A-b,w=e.slice(k,x),_.index-=k}else{h.lastIndex=0;var _=h.exec(w),I=1}if(_){d&&(p=_[1]?_[1].length:0);var j=_.index+p,_=_[0].slice(p),P=j+_.length,N=w.slice(0,j),S=w.slice(P),C=[b,I];N&&(++b,k+=N.length,C.push(N));var E=new s(u,f?n.tokenize(_,f):_,y,_,m);if(C.push(E),S&&C.push(S),Array.prototype.splice.apply(t,C),1!=I&&n.matchGrammar(e,t,r,b,k,!0,u),i)break}else if(i)break}}}}},tokenize:function(e,t){var r=[e],a=t.rest;if(a){for(var l in a)t[l]=a[l];delete t.rest}return n.matchGrammar(e,r,t,0,0,!1),r},hooks:{all:{},add:function(e,t){var r=n.hooks.all;r[e]=r[e]||[],r[e].push(t)},run:function(e,t){var r=n.hooks.all[e];if(r&&r.length)for(var a,l=0;a=r[l++];)a(t)}}},r=n.Token=function(e,t,n,r,a){this.type=e,this.content=t,this.alias=n,this.length=0|(r||"").length,this.greedy=!!a};if(r.stringify=function(e,t,a){if("string"==typeof e)return e;if("Array"===n.util.type(e))return e.map(function(n){return r.stringify(n,t,e)}).join("");var l={type:e.type,content:r.stringify(e.content,t,a),tag:"span",classes:["token",e.type],attributes:{},language:t,parent:a};if(e.alias){var i="Array"===n.util.type(e.alias)?e.alias:[e.alias];Array.prototype.push.apply(l.classes,i)}n.hooks.run("wrap",l);var o=Object.keys(l.attributes).map(function(e){return e+'="'+(l.attributes[e]||"").replace(/"/g,""")+'"'}).join(" ");return"<"+l.tag+' class="'+l.classes.join(" ")+'"'+(o?" "+o:"")+">"+l.content+""},!_self.document)return _self.addEventListener?(n.disableWorkerMessageHandler||_self.addEventListener("message",function(e){var t=JSON.parse(e.data),r=t.language,a=t.code,l=t.immediateClose;_self.postMessage(n.highlight(a,n.languages[r],r)),l&&_self.close()},!1),_self.Prism):_self.Prism;var a=document.currentScript||[].slice.call(document.getElementsByTagName("script")).pop();return a&&(n.filename=a.src,n.manual||a.hasAttribute("data-manual")||("loading"!==document.readyState?window.requestAnimationFrame?window.requestAnimationFrame(n.highlightAll):window.setTimeout(n.highlightAll,16):document.addEventListener("DOMContentLoaded",n.highlightAll))),_self.Prism}();"undefined"!=typeof module&&module.exports&&(module.exports=Prism),"undefined"!=typeof global&&(global.Prism=Prism); 4 | Prism.languages.clike={comment:[{pattern:/(^|[^\\])\/\*[\s\S]*?(?:\*\/|$)/,lookbehind:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0,greedy:!0}],string:{pattern:/(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},"class-name":{pattern:/((?:\b(?:class|interface|extends|implements|trait|instanceof|new)\s+)|(?:catch\s+\())[\w.\\]+/i,lookbehind:!0,inside:{punctuation:/[.\\]/}},keyword:/\b(?:if|else|while|do|for|return|in|instanceof|function|new|try|throw|catch|finally|null|break|continue)\b/,"boolean":/\b(?:true|false)\b/,"function":/[a-z0-9_]+(?=\()/i,number:/\b0x[\da-f]+\b|(?:\b\d+\.?\d*|\B\.\d+)(?:e[+-]?\d+)?/i,operator:/--?|\+\+?|!=?=?|<=?|>=?|==?=?|&&?|\|\|?|\?|\*|\/|~|\^|%/,punctuation:/[{}[\];(),.:]/}; 5 | Prism.languages.java=Prism.languages.extend("clike",{keyword:/\b(?:var|abstract|continue|for|new|switch|assert|default|goto|package|synchronized|boolean|do|if|private|this|break|double|implements|protected|throw|byte|else|import|public|throws|case|enum|instanceof|return|transient|catch|extends|int|short|try|char|final|interface|static|void|class|finally|long|strictfp|volatile|const|float|native|super|while)\b/,number:/\b0b[01]+\b|\b0x[\da-f]*\.?[\da-fp-]+\b|(?:\b\d+\.?\d*|\B\.\d+)(?:e[+-]?\d+)?[df]?/i,operator:{pattern:/(^|[^.])(?:<<=?|>>>?=?|->|([-+&|])\2|[?:~]|[-+*\/%&|^!=<>]=?)/m,lookbehind:!0}}),Prism.languages.insertBefore("java","function",{annotation:{alias:"punctuation",pattern:/(^|[^.])@\w+/,lookbehind:!0}}),Prism.languages.insertBefore("java","class-name",{generics:{pattern:/<\s*\w+(?:\.\w+)?(?:\s*,\s*\w+(?:\.\w+)?)*>/i,alias:"function",inside:{keyword:Prism.languages.java.keyword,punctuation:/[<>(),.:]/}}}); 6 | Prism.languages.scala=Prism.languages.extend("java",{keyword:/<-|=>|\b(?:abstract|case|catch|class|def|do|else|extends|final|finally|for|forSome|if|implicit|import|lazy|match|new|null|object|override|package|private|protected|return|sealed|self|super|this|throw|trait|try|type|val|var|while|with|yield)\b/,string:[{pattern:/"""[\s\S]*?"""/,greedy:!0},{pattern:/("|')(?:\\.|(?!\1)[^\\\r\n])*\1/,greedy:!0}],builtin:/\b(?:String|Int|Long|Short|Byte|Boolean|Double|Float|Char|Any|AnyRef|AnyVal|Unit|Nothing)\b/,number:/\b0x[\da-f]*\.?[\da-f]+|(?:\b\d+\.?\d*|\B\.\d+)(?:e\d+)?[dfl]?/i,symbol:/'[^\d\s\\]\w*/}),delete Prism.languages.scala["class-name"],delete Prism.languages.scala["function"]; 7 | !function(){if("undefined"!=typeof self&&self.Prism&&self.document){var e="line-numbers",t=/\n(?!$)/g,n=function(e){var n=r(e),s=n["white-space"];if("pre-wrap"===s||"pre-line"===s){var l=e.querySelector("code"),i=e.querySelector(".line-numbers-rows"),a=e.querySelector(".line-numbers-sizer"),o=l.textContent.split(t);a||(a=document.createElement("span"),a.className="line-numbers-sizer",l.appendChild(a)),a.style.display="block",o.forEach(function(e,t){a.textContent=e||"\n";var n=a.getBoundingClientRect().height;i.children[t].style.height=n+"px"}),a.textContent="",a.style.display="none"}},r=function(e){return e?window.getComputedStyle?getComputedStyle(e):e.currentStyle||null:null};window.addEventListener("resize",function(){Array.prototype.forEach.call(document.querySelectorAll("pre."+e),n)}),Prism.hooks.add("complete",function(e){if(e.code){var r=e.element.parentNode,s=/\s*\bline-numbers\b\s*/;if(r&&/pre/i.test(r.nodeName)&&(s.test(r.className)||s.test(e.element.className))&&!e.element.querySelector(".line-numbers-rows")){s.test(e.element.className)&&(e.element.className=e.element.className.replace(s," ")),s.test(r.className)||(r.className+=" line-numbers");var l,i=e.code.match(t),a=i?i.length+1:1,o=new Array(a+1);o=o.join(""),l=document.createElement("span"),l.setAttribute("aria-hidden","true"),l.className="line-numbers-rows",l.innerHTML=o,r.hasAttribute("data-start")&&(r.style.counterReset="linenumber "+(parseInt(r.getAttribute("data-start"),10)-1)),e.element.appendChild(l),n(r),Prism.hooks.run("line-numbers",e)}}}),Prism.hooks.add("line-numbers",function(e){e.plugins=e.plugins||{},e.plugins.lineNumbers=!0}),Prism.plugins.lineNumbers={getLine:function(t,n){if("PRE"===t.tagName&&t.classList.contains(e)){var r=t.querySelector(".line-numbers-rows"),s=parseInt(t.getAttribute("data-start"),10)||1,l=s+(r.children.length-1);s>n&&(n=s),n>l&&(n=l);var i=n-s;return r.children[i]}}}}}(); 8 | -------------------------------------------------------------------------------- /public/stylesheets/main.css: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2009-2017 Lightbend Inc. 3 | */ 4 | html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,font,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td{margin:0;padding:0;border:0;outline:0;font-weight:inherit;font-style:inherit;font-size:100%;font-family:inherit;} 5 | table{border-collapse:collapse;border-spacing:0;} 6 | caption,th,td{text-align:left;font-weight:normal;} 7 | form legend{display:none;} 8 | blockquote:before,blockquote:after,q:before,q:after{content:"";} 9 | blockquote,q{quotes:"" "";} 10 | ol,ul{list-style:none;} 11 | hr{display:none;visibility:hidden;} 12 | :focus{outline:0;} 13 | article{}article h1,article h2,article h3,article h4,article h5,article h6{color:#333;font-weight:bold;line-height:1.25;margin-top:1.3em;} 14 | article h1 a,article h2 a,article h3 a,article h4 a,article h5 a,article h6 a{font-weight:inherit;color:#333;}article h1 a:hover,article h2 a:hover,article h3 a:hover,article h4 a:hover,article h5 a:hover,article h6 a:hover{color:#333;} 15 | article h1{font-size:36px;margin:0 0 18px;border-bottom:4px solid #eee;} 16 | article h2{font-size:25px;margin-bottom:9px;border-bottom:2px solid #eee;} 17 | article h3{font-size:18px;margin-bottom:9px;} 18 | article h4{font-size:15px;margin-bottom:3px;} 19 | article h5{font-size:12px;font-weight:normal;margin-bottom:3px;} 20 | article .subheader{color:#777;font-weight:300;margin-bottom:24px;} 21 | article p{line-height:1.3em;margin:1em 0;} 22 | article p img{margin:0;} 23 | article p.lead{font-size:18px;font-size:1.8rem;line-height:1.5;} 24 | article li>p:first-child{margin-top:0;} 25 | article li>p:last-child{margin-bottom:0;} 26 | article ul li,article ol li{position:relative;padding:4px 0 4px 14px;}article ul li ol,article ol li ol,article ul li ul,article ol li ul{margin-left:20px;} 27 | article ul li:before,article ol li:before{position:absolute;top:8px;left:0;content:"►";color:#ccc;font-size:10px;margin-right:5px;} 28 | article>ol{counter-reset:section;}article>ol li:before{color:#ccc;font-size:13px;} 29 | article>ol>li{padding:6px 0 4px 20px;counter-reset:chapter;}article>ol>li:before{content:counter(section) ".";counter-increment:section;} 30 | article>ol>li>ol>li{padding:6px 0 4px 30px;counter-reset:item;}article>ol>li>ol>li:before{content:counter(section) "." counter(chapter);counter-increment:chapter;} 31 | article>ol>li>ol>li>ol>li{padding:6px 0 4px 40px;}article>ol>li>ol>li>ol>li:before{content:counter(section) "." counter(chapter) "." counter(item);counter-increment:item;} 32 | article em,article i{font-style:italic;line-height:inherit;} 33 | article strong,article b{font-weight:bold;line-height:inherit;} 34 | article small{font-size:60%;line-height:inherit;} 35 | article h1 small,article h2 small,article h3 small,article h4 small,article h5 small{color:#777;} 36 | article hr{border:solid #ddd;border-width:1px 0 0;clear:both;margin:12px 0 18px;height:0;} 37 | article abbr,article acronym{text-transform:uppercase;font-size:90%;color:#222;border-bottom:1px solid #ddd;cursor:help;} 38 | article abbr{text-transform:none;} 39 | article img{max-width:100%;} 40 | article pre{margin:10px 0;border:1px solid #ddd;padding:10px;background:#fafafa;color:#666;overflow:auto;border-radius:5px;} 41 | article code{background:#fafafa;color:#666;font-family:inconsolata, monospace;border:1px solid #ddd;border-radius:3px;height:4px;padding:0;} 42 | article a code{color:#80c846;}article a code:hover{color:#6dae38;} 43 | article pre code{border:0;background:inherit;border-radius:0;line-height:inherit;font-size:14px;} 44 | article pre.prettyprint{border:1px solid #ddd;padding:10px;} 45 | article blockquote,article blockquote p,article p.note{line-height:20px;color:#4c4742;} 46 | article blockquote,article .note{margin:0 0 18px;padding:1px 20px;background:#fff7d6;}article blockquote li:before,article .note li:before{color:#e0bc6f;} 47 | article blockquote code,article .note code{background:#f5d899;border:none;color:inherit;} 48 | article blockquote a,article .note a{color:#6dae38;} 49 | article blockquote pre,article .note pre{background:#F5D899 !important;color:#48484C !important;border:none !important;} 50 | article p.note{padding:15px 20px;} 51 | article table{width:100%;}article table td{padding:8px;} 52 | article table tr{background:#F4F4F7;border-bottom:1px solid #eee;} 53 | article table tr:nth-of-type(odd){background:#fafafa;} 54 | article dl dt{font-weight:bold;} 55 | article dl.tabbed{position:relative;} 56 | article dl.tabbed dt{float:left;margin:0 5px 0 0;border:1px solid #ddd;padding:0 20px;line-height:2;border-radius: 5px 5px 0 0;} 57 | article dl.tabbed dt a{display:block;height:30px;color:#333;text-decoration:none;} 58 | article dl.tabbed dt.current{background: #f7f7f7;} 59 | article dl.tabbed dd{position:absolute;width:100%;left:0;top:30px;} 60 | article dl.tabbed dd pre{margin-top:0;border-top-left-radius:0;} 61 | a{color:#80c846;}a:hover{color:#6dae38;} 62 | p{margin:1em 0;} 63 | h1{-webkit-font-smoothing:antialiased;} 64 | h2{font-weight:bold;font-size:28px;} 65 | hr{clear:both;margin:20px 0 25px 0;border:none;border-top:1px solid #444;visibility:visible;display:block;} 66 | section{padding:50px 0;} 67 | body{background:#f5f5f5;background:#fff;color:#555;font:15px "Helvetica Nueue",sans-serif;} 68 | .wrapper{width:80%;margin:0 auto;box-sizing:border-box;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;padding:60px 0;}.wrapper:after{content:" ";display:block;clear:both;} 69 | .wrapper article{min-height:310px;width:60%;float:left;} 70 | .wrapper aside{width:20%;float:right;}.wrapper aside ul{margin:2px 0 30px;}.wrapper aside ul a{display:block;padding:3px 0 3px 10px;margin:2px 0;border-left:4px solid #eee;}.wrapper aside ul a:hover{border-color:#80c846;} 71 | .wrapper aside h3{font-size:18px;color:#333;font-weight:bold;line-height:2em;margin:32px 9px 0;border-bottom:1px solid #eee;} 72 | .wrapper aside.stick{position:fixed;right:50%;margin-right:-480px;top:120px;bottom:0;overflow:hidden;} 73 | .half{width:50%;float:left;box-sizing:border-box;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;} 74 | header{position:fixed;top:0;z-index:1000;width:100%;height:50px;line-height:50px;padding:30px 0;background:#fff;background:rgba(255, 255, 255, 0.95);border-bottom:1px solid #ccc;box-shadow:0 4px 0 rgba(0, 0, 0, 0.1);}header #logo{position:absolute;left:50%;margin-left:-480px;} 75 | header nav{position:absolute;right:50%;margin-right:-480px;}header nav a{padding:0 10px 4px;font-size:21px;font-weight:500;text-decoration:none;} 76 | header nav a.selected{border-bottom:3px solid #E9E9E9;} 77 | header nav a.download{position:relative;background:#80c846;color:white;margin-left:10px;padding:5px 10px 2px;font-weight:700;border-radius:5px;box-shadow:0 3px 0 #6dae38;text-shadow:-1px -1px 0 rgba(0, 0, 0, 0.2);-webkit-transition:all 70ms ease-out;border:0;}header nav a.download:hover{box-shadow:0 3px 0 #6dae38,0 3px 4px rgba(0, 0, 0, 0.3);} 78 | header nav a.download:active{box-shadow:0 1px 0 #6dae38;top:2px;-webkit-transition:none;} 79 | #download,#getLogo{display:none;position:absolute;padding:5px 20px;width:200px;background:#000;background:rgba(0, 0, 0, 0.8);border-radius:5px;color:#999;line-height:15px;}#download a,#getLogo a{color:#ccc;text-decoration:none;}#download a:hover,#getLogo a:hover{color:#fff;} 80 | #getLogo{text-align:center;}#getLogo h3{font-size:16px;color:#80c846;margin:0 0 15px;} 81 | #getLogo figure{border-radius:3px;margin:5px 0;padding:5px;background:#fff;line-height:25px;width:80px;display:inline-block;}#getLogo figure a{color:#999;text-decoration:none;}#getLogo figure a:hover{color:#666;} 82 | #download{top:85px;right:50%;margin-right:-480px;}#download .button{font-size:16px;color:#80c846;} 83 | #getLogo{top:85px;left:50%;padding:20px;margin-left:-480px;}#getLogo ul{margin:5px 0;} 84 | #getLogo li{margin:1px 0;} 85 | #news{background:#f5f5f5;color:#999;font-size:17px;box-shadow:0 1px 0 rgba(0, 0, 0, 0.1);position:relative;z-index:2;padding:3px 0;}#news ul{box-sizing:border-box;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;background:url(/assets/images/news.png) 10px center no-repeat;padding:19px 0 19px 60px;} 86 | #content{padding:15px 0;} 87 | #top{background:#80c846 url(/assets/images/header-pattern.png) fixed;box-shadow:0 -4px 0 rgba(0, 0, 0, 0.1) inset;padding:0;position:relative;}#top .wrapper{padding:30px 0;} 88 | #top h1{float:left;padding-top:15px;color:#fff;font-size:35px;line-height:48px;text-shadow:2px 2px 0 rgba(0, 0, 0, 0.1);margin-left:10px;}#top h1 a{text-decoration:none;color:#fff;} 89 | #top nav{float:right;margin-top:10px;line-height:25px;}#top nav .versions,#top nav form{float:left;margin:0 5px;} 90 | #top nav .versions{height:25px;display:inline-block;border:1px solid #6dae38;border-radius:3px;background:#80c846;background:-moz-linear-gradient(top, #80c846 0%, #6dae38 100%);background:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #80c846), color-stop(100%, #6dae38));background:-webkit-linear-gradient(top, #80c846 0%, #6dae38 100%);background:-o-linear-gradient(top, #80c846 0%, #6dae38 100%);background:-ms-linear-gradient(top, #80c846 0%, #6dae38 100%);background:linear-gradient(top, #80c846 0%, #6dae38 100%);filter:progid:DXImageTransform.Microsoft.gradient( startColorstr='#80c846', endColorstr='#6dae38',GradientType=0 );box-shadow:inset 0 -1px 1px #80c846;text-align:center;color:#fff;text-shadow:-1px -1px 0 #6dae38;}#top nav .versions span{padding:0 4px;position:absolute;}#top nav .versions span:before{content:"⬍";color:rgba(0, 0, 0, 0.4);text-shadow:1px 1px 0 #80c846;margin-right:4px;} 91 | #top nav .versions select{opacity:0;position:relative;z-index:9;} 92 | #top .follow{display:inline-block;border:1px solid #6dae38;border-radius:3px;background:#80c846;background:-moz-linear-gradient(top, #80c846 0%, #6dae38 100%);background:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #80c846), color-stop(100%, #6dae38));background:-webkit-linear-gradient(top, #80c846 0%, #6dae38 100%);background:-o-linear-gradient(top, #80c846 0%, #6dae38 100%);background:-ms-linear-gradient(top, #80c846 0%, #6dae38 100%);background:linear-gradient(top, #80c846 0%, #6dae38 100%);filter:progid:DXImageTransform.Microsoft.gradient( startColorstr='#80c846', endColorstr='#6dae38',GradientType=0 );box-shadow:inset 0 -1px 1px #80c846;text-align:center;vertical-align:middle;color:#fff;text-shadow:-1px -1px 0 #6dae38;padding:4px 8px;text-decoration:none;position:absolute;top:41px;left:50%;margin-left:210px;width:250px;}#top .follow:before{vertical-align:middle;content:url(/assets/images/twitter.png);margin-right:10px;} 93 | #top input{width:80px;-webkit-transition:width 200ms ease-in-out;-moz-transition:width 200ms ease-in-out;}#top input:focus{width:200px;} 94 | #title{width:500px;float:left;font-size:17px;color:#2d6201;} 95 | #quicklinks{width:350px;margin:-15px 0 0 0;box-sizing:border-box;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;float:right;padding:30px;background:#fff;color:#888;box-shadow:0 3px 5px rgba(0, 0, 0, 0.2);}#quicklinks h2{color:#80c846;font-size:20px;margin-top:15px;padding:10px 0 5px 0;border-top:1px solid #eee;}#quicklinks h2:first-child{margin:0;padding:0 0 5px 0;border:0;} 96 | #quicklinks p{margin:0;} 97 | #quicklinks a{color:#444;}#quicklinks a:hover{color:#222;} 98 | .tweet{border-bottom:1px solid #eee;padding:6px 0 20px 60px;position:relative;min-height:50px;margin-bottom:20px;}.tweet img{position:absolute;left:0;top:8px;} 99 | .tweet strong{font-size:14px;font-weight:bold;} 100 | .tweet span{font-size:12px;color:#888;} 101 | .tweet p{padding:0;margin:5px 0 0 0;} 102 | footer{padding:40px 0;background:#363736;background:#eee;border-top:1px solid #e5e5e5;color:#aaa;position:relative;}footer .logo{position:absolute;top:55px;left:50%;margin-left:-480px;-webkit-transform:translate3d(0, 0, 0);-moz-transform:translate3d(0, 0, 0);transform:translate3d(0, 0, 0);} 103 | footer:after{content:" ";display:block;clear:both;} 104 | footer .links{width:960px;margin:0 auto;box-sizing:border-box;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;margin:0 auto;padding-left:200px;}footer .links:after{content:" ";display:block;clear:both;} 105 | footer .links dl{width:33%;box-sizing:border-box;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;padding:0 10px;float:left;} 106 | footer .links dt{color:#80c846;font-weight:bold;} 107 | footer .links a{color:#aaa;text-decoration:none;}footer .links a:hover{color:#888;} 108 | footer .licence{width:960px;margin:0 auto;box-sizing:border-box;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;margin:20px auto 0;padding-top:20px;border-top:2px solid #ddd;font-size:12px;}footer .licence:after{content:" ";display:block;clear:both;} 109 | footer .licence .typesafe,footer .licence .zenexity{float:right;} 110 | footer .licence .typesafe{position:relative;top:-3px;margin-left:10px;} 111 | footer .licence a{color:#999;} 112 | div.coreteam{position:relative;min-height:80px;border-bottom:1px solid #eee;}div.coreteam img{width:50px;position:absolute;left:0;top:0;padding:2px;border:1px solid #ddd;} 113 | div.coreteam a{color:inherit;text-decoration:none;} 114 | div.coreteam h2{padding-left:70px;border:none;font-size:20px;} 115 | div.coreteam p{margin-top:5px;padding-left:70px;} 116 | ul.contributors{padding:0;margin:0;list-style:none;}ul.contributors li{padding:6px 0 !important;margin:0;}ul.contributors li:before{content:' ';} 117 | ul.contributors img{width:25px;padding:1px;border:1px solid #ddd;margin-right:5px;vertical-align:middle;} 118 | ul.contributors a{color:inherit;text-decoration:none;} 119 | ul.contributors span{font-weight:bold;color:#666;} 120 | ul.contributors.others li{display:inline-block;width:32.3333%;} 121 | div.list{float:left;width:33.3333%;margin-bottom:30px;} 122 | h2{clear:both;} 123 | span.by{font-size:14px;font-weight:normal;} 124 | form dl{padding:10px 0;} 125 | dd.info{color:#888;font-size:12px;} 126 | dd.error{color:#c00;} 127 | aside a[href^="http"]:after,.doc a[href^="http"]:after{content:url(/assets/images/external.png);vertical-align:middle;margin-left:5px;} 128 | img.resize{width:44.8px;height74.18px;float:left;} 129 | --------------------------------------------------------------------------------