From e0c7b18483dda0cec4b9326a81bc72a35cd052f8 Mon Sep 17 00:00:00 2001 From: Artem Medeu Date: Tue, 4 Jan 2011 12:39:53 +0600 Subject: [PATCH] [#526] Added cheat sheet support to standard docviewer module Each cheat sheet could be accessed via url '@documentation/cheatsheets/{category}' --- .../ch25-CommandLinePlayCommand.textile | 85 +++++++++++++++++ .../ch01-ControllerActionSmartbinding.textile | 27 ++++++ .../ch02-ControllerActionValidation.textile | 20 ++++ .../ch03-ControllerSessionManagement.textile | 28 ++++++ .../ch04-ControllerActionRedirection.textile | 23 +++++ .../controllers/ch05-ControllerJobs.textile | 7 ++ .../ch06-ControllerInterceptions.textile | 14 +++ .../ch07-ControllerActionOthers.textile | 16 ++++ .../ch08-ControllerLibraries.textile | 58 ++++++++++++ .../model/ch14-ModelActionQueries.textile | 33 +++++++ .../model/ch15-ModelBasics.textile | 20 ++++ .../model/ch16-ModelGenerators.textile | 14 +++ .../model/ch17-ModelRelationalMapping.textile | 33 +++++++ .../model/ch18-ModelCallbacks.textile | 25 +++++ .../model/ch19-ModelRelations.textile | 29 ++++++ .../model/ch20-ModelJPAQueries.textile | 13 +++ .../ch26-MultiEnvironment.textile | 15 +++ .../ch09-TemplateImplicitObjects.textile | 29 ++++++ .../templates/ch10-TemplateTagGrammar.textile | 26 ++++++ .../ch11-TemplateStandardTags.textile | 53 +++++++++++ .../templates/ch12-TemplateCustomTags.textile | 9 ++ .../ch13-TemplateGroovyExtension.textile | 80 ++++++++++++++++ .../tests/ch21-TestUnitTests.textile | 25 +++++ .../tests/ch22-TestFunctionalTests.textile | 17 ++++ .../tests/ch23-TestSeleniumTests.textile | 14 +++ .../tests/ch24-TestDataloader.textile | 10 ++ documentation/manual/home.textile | 6 ++ modules/docviewer/app/DocViewerPlugin.java | 1 + .../app/controllers/PlayDocumentation.java | 21 ++++- .../app/helpers/CheatSheetHelper.java | 89 ++++++++++++++++++ .../views/PlayDocumentation/cheatSheet.html | 48 ++++++++++ .../public/playmanual/cheat-sheet.css | 92 +++++++++++++++++++ 32 files changed, 978 insertions(+), 2 deletions(-) create mode 100644 documentation/cheatsheets/commandLine/ch25-CommandLinePlayCommand.textile create mode 100644 documentation/cheatsheets/controllers/ch01-ControllerActionSmartbinding.textile create mode 100644 documentation/cheatsheets/controllers/ch02-ControllerActionValidation.textile create mode 100644 documentation/cheatsheets/controllers/ch03-ControllerSessionManagement.textile create mode 100644 documentation/cheatsheets/controllers/ch04-ControllerActionRedirection.textile create mode 100644 documentation/cheatsheets/controllers/ch05-ControllerJobs.textile create mode 100644 documentation/cheatsheets/controllers/ch06-ControllerInterceptions.textile create mode 100644 documentation/cheatsheets/controllers/ch07-ControllerActionOthers.textile create mode 100644 documentation/cheatsheets/controllers/ch08-ControllerLibraries.textile create mode 100644 documentation/cheatsheets/model/ch14-ModelActionQueries.textile create mode 100644 documentation/cheatsheets/model/ch15-ModelBasics.textile create mode 100644 documentation/cheatsheets/model/ch16-ModelGenerators.textile create mode 100644 documentation/cheatsheets/model/ch17-ModelRelationalMapping.textile create mode 100644 documentation/cheatsheets/model/ch18-ModelCallbacks.textile create mode 100644 documentation/cheatsheets/model/ch19-ModelRelations.textile create mode 100644 documentation/cheatsheets/model/ch20-ModelJPAQueries.textile create mode 100644 documentation/cheatsheets/multiEnvironment/ch26-MultiEnvironment.textile create mode 100644 documentation/cheatsheets/templates/ch09-TemplateImplicitObjects.textile create mode 100644 documentation/cheatsheets/templates/ch10-TemplateTagGrammar.textile create mode 100644 documentation/cheatsheets/templates/ch11-TemplateStandardTags.textile create mode 100644 documentation/cheatsheets/templates/ch12-TemplateCustomTags.textile create mode 100644 documentation/cheatsheets/templates/ch13-TemplateGroovyExtension.textile create mode 100644 documentation/cheatsheets/tests/ch21-TestUnitTests.textile create mode 100644 documentation/cheatsheets/tests/ch22-TestFunctionalTests.textile create mode 100644 documentation/cheatsheets/tests/ch23-TestSeleniumTests.textile create mode 100644 documentation/cheatsheets/tests/ch24-TestDataloader.textile create mode 100644 modules/docviewer/app/helpers/CheatSheetHelper.java create mode 100644 modules/docviewer/app/views/PlayDocumentation/cheatSheet.html create mode 100644 modules/docviewer/public/playmanual/cheat-sheet.css diff --git a/documentation/cheatsheets/commandLine/ch25-CommandLinePlayCommand.textile b/documentation/cheatsheets/commandLine/ch25-CommandLinePlayCommand.textile new file mode 100644 index 0000000000..58f2f07b3d --- /dev/null +++ b/documentation/cheatsheets/commandLine/ch25-CommandLinePlayCommand.textile @@ -0,0 +1,85 @@ +h2. Command line - play command + +*classpath* +Display the computed classpath + +*id* +Define the framework ID, used for multi environment config + +*secret* +Generate a new secret key, used for encryption + +*install* +Install a module + +*list-modules* +List modules available from the central modules repository + +*modules* +Display the computed modules list + +*new* +Create a new application + +*new-module* +Create a module + +*build-module* +Build and package a module + +*eclipsify* +Create all Eclipse configuration files + +*netbeansify* +Create all NetBeans configuration files + +*idealize* +Create all IntelliJ Idea configuration files + +*javadoc* +Generate your application Javadoc + +*auto-test* +Automatically run all application tests + +*clean* +Delete temporary files (including the bytecode cache) + +*test* +Run the application in test mode in the current shell + +*precompile* +Precompile all Java sources and templates to speed up +application start-up + +*war* +Export the application as a standalone WAR archive + +*run* +Run the application in the current shell + +*start* +Start the application in the background + +*stop* +Stop the running application + +*restart* +Restart the running application + +*status* +Display the running application's status + +*out* +Follow logs/system.out file + +*pid* +Show the PID of the running application + +*check* +Check for a release newer than the current one + +*help* +Display help on a specific command + + diff --git a/documentation/cheatsheets/controllers/ch01-ControllerActionSmartbinding.textile b/documentation/cheatsheets/controllers/ch01-ControllerActionSmartbinding.textile new file mode 100644 index 0000000000..b8aa213b9f --- /dev/null +++ b/documentation/cheatsheets/controllers/ch01-ControllerActionSmartbinding.textile @@ -0,0 +1,27 @@ +h2. Controller.action - Smart binding + +*==Controller/link?i=32&n=patrick==* +==public static void link(int i, String n)== +==public static void link(Integer i, String n)== +==public static void link(Long i, String n)== + +*==Controller/show?id[0]=1&id[1]=2&id[2]=3&id[3]=4==* +==public static void show(Long[] id)== +==public static void show(List id)== +==public static void show(Set id)== + +*==Controller/get?date=02-18-1972==* +==public static void get(@As("MM-dd-yyyy") Date date)== + +*==(@As(binder=MyCustomStringBinder.class))==* +Custom parameter binder + +*Send File as multipart/form-data encoded post request* +public static void create(String comment, File attachment) + +*==?client.name=paul&client.email=contact@crionics.com==* +public static void create(Client client) POJO binding + +*@NoBinding* +Marks a non bindable field + diff --git a/documentation/cheatsheets/controllers/ch02-ControllerActionValidation.textile b/documentation/cheatsheets/controllers/ch02-ControllerActionValidation.textile new file mode 100644 index 0000000000..ca908b9907 --- /dev/null +++ b/documentation/cheatsheets/controllers/ch02-ControllerActionValidation.textile @@ -0,0 +1,20 @@ +h2. Controller.action - Validation + +*==@Required String lastname==* +*==@IsTrue String agree==* +*==@Max(7500) Integer wordCount==* +*==@Min(18) Long age==* +*==@MaxSize(2083) String value==* +*==@MinSize(42) String value==* +*==@Email String address==* +*==@Equals("passwordConfirmation") String password==* +*==@InFuture String dueDate==* +*==@InFuture("1979-12-31") String birthDate==* +*==@Match("[A-Z]{3}") String abbreviation==* +*==@Match("(directDebit|creditCard|onReceipt)")==* +*==@Past String actualDepartureDate==* +*==@Past("1980-01-01") String birthDate==* +*==@Range(min = 17500, max = 40000) String wordCount==* +*==@URL String address==* +*==@Valid Person person==* +Pojo validation - class Person needs validation annotations diff --git a/documentation/cheatsheets/controllers/ch03-ControllerSessionManagement.textile b/documentation/cheatsheets/controllers/ch03-ControllerSessionManagement.textile new file mode 100644 index 0000000000..7ffa14052b --- /dev/null +++ b/documentation/cheatsheets/controllers/ch03-ControllerSessionManagement.textile @@ -0,0 +1,28 @@ +h2. Controller - Session Management + +*WARNING: Play Session is NOT the J2EE session* +session and flash use cookies! 4kb limit/20 cookies max + +*session.getId();* +Returns the session Id - in most cases: a must have! + +*session.put(String key, String value);* +*session.get("user_flag");* +Values are limited to Strings, 4kb max + +*flash.put(String key, String value);* +*flash.get(String key);* +Flash entries are discarded at end of next call + +*Cache.set("key_" + id, product, "30mn");* +Set cache value for 30 minutes + +*Cache.get("key_" + id, Product.class);* +Get cache value, may return null + +*Cache.delete("key_" + id);* +Non blocking cache delete + +*Cache.safeDelete("key_" + id);* +Blocking cache delete + diff --git a/documentation/cheatsheets/controllers/ch04-ControllerActionRedirection.textile b/documentation/cheatsheets/controllers/ch04-ControllerActionRedirection.textile new file mode 100644 index 0000000000..f034212fb5 --- /dev/null +++ b/documentation/cheatsheets/controllers/ch04-ControllerActionRedirection.textile @@ -0,0 +1,23 @@ +h2. Controller.action - Redirection + +*render(params...);* +Renders template with given parameters, text/html + +*renderXML(params...);* +Renders parameters as application/xml + +*renderJson(params...);* +Renders parameters as application/json + +*renderText(params...);* +Renders parameters as text/plain + +*renderTemplate("Clients/showClient.html", id, client);* +Bypasses default template + +*redirect("http://www.crionics.com");* +Http redirect to the given URL + +*From an action, calling another Controller.action()* +The framework transparently generates a REDIRECT! + diff --git a/documentation/cheatsheets/controllers/ch05-ControllerJobs.textile b/documentation/cheatsheets/controllers/ch05-ControllerJobs.textile new file mode 100644 index 0000000000..531888e882 --- /dev/null +++ b/documentation/cheatsheets/controllers/ch05-ControllerJobs.textile @@ -0,0 +1,7 @@ +h2. Controller - Jobs + +*==@OnApplicationStart==* +*==@On("0 0 12 ∗ ∗ ?")==* +*==@Every("1h")==* +==public class Bootstrap extends Job {public void doJob() {...} }== + diff --git a/documentation/cheatsheets/controllers/ch06-ControllerInterceptions.textile b/documentation/cheatsheets/controllers/ch06-ControllerInterceptions.textile new file mode 100644 index 0000000000..d57dd2cf80 --- /dev/null +++ b/documentation/cheatsheets/controllers/ch06-ControllerInterceptions.textile @@ -0,0 +1,14 @@ +h2. Controller - Interceptions + +*==@Before ➟ action ➟ @After ➟ template ➟ @Finally==* +Interceptions evaluation order + +*==@Before static void checkAuthentification()==* +*==@After static void log()==* +*==@Finally static void audit()==* +You get the idea + +*==@With(Secure.class)==* +*==public class Admin extends Application==* +Custom interceptors at the controller scope + diff --git a/documentation/cheatsheets/controllers/ch07-ControllerActionOthers.textile b/documentation/cheatsheets/controllers/ch07-ControllerActionOthers.textile new file mode 100644 index 0000000000..ee8a9296f1 --- /dev/null +++ b/documentation/cheatsheets/controllers/ch07-ControllerActionOthers.textile @@ -0,0 +1,16 @@ +h2. Controller.action - Others + +*==Logger.info("Action executed ...");==* +*==Logger.debug("A log message");==* +*==Logger.error(ex, "Oops");==* +Logging configuration lives in application.conf + +*==@CacheFor("1h") public static void index() { ... }==* +Caches the result of the action for 1h + +*==Play.configuration.getProperty("blog.title");==* +Access to the configuration file + +*==Query query = JPA.em().createQuery(“query”);==* +Access the persistence manager + diff --git a/documentation/cheatsheets/controllers/ch08-ControllerLibraries.textile b/documentation/cheatsheets/controllers/ch08-ControllerLibraries.textile new file mode 100644 index 0000000000..cc64533a4f --- /dev/null +++ b/documentation/cheatsheets/controllers/ch08-ControllerLibraries.textile @@ -0,0 +1,58 @@ +h2. Controller - Libraries + +*==WS.url(“http://s.com/posts”).get().toJSON();==* +HTTP get request to JSON + +*==WS.url(“http://s.com/”).post().toXML();==* +HTTP post request to XML + +*==XML.getDocument(String);==* +String to XML + +*==XML.serialize(Document);==* +XML to String + +*==XPath.selectNodes(String xpath, Object node);==* +XPath expression evaluator + +*==Files.copy(File,File);==* +File copy + +*==Files.copyDir(File,File);==* +Recursive directory copy + +*==Files.delete(File);==* +*==Files.deleteDirectory(File);==* +Deletes file/directory + +*==IO.readLines(File);==* +*==IO.readContentAsString(File);==* +*==IO.readContent(File);==* +*==IO.write(byte[],File);==* +Read/Write file contents + +*==Images.crop(File orig,File to, int x1, int y1, int x2, int y2);==* +*==Images.resize(File orig, File to, int w, int h);==* +*==Images.toBase64(File image);==* +Handy methods! + +*==Crypto.encryptAES(String);==* +*==Crypto.decryptAES(String);==* +Encryption using the application secret key + +*==Crypto.passwordHash(String);==* +Create an MD5 password hash + +*==Codec.UUID();==* +Generates unique IDs + +*==Codec.byteToHexString(byte[] bytes);==* +Write a byte array as hexadecimal String + +*==Codec.encodeBASE64(byte[] value);==* +*==Codec.decodeBASE64(String base64);==* +Encode/Decode a base64 value + +*==Codec.hexSHA1(String);==* +Build a hexadecimal SHA1 hash for a String + diff --git a/documentation/cheatsheets/model/ch14-ModelActionQueries.textile b/documentation/cheatsheets/model/ch14-ModelActionQueries.textile new file mode 100644 index 0000000000..6a6d273f1b --- /dev/null +++ b/documentation/cheatsheets/model/ch14-ModelActionQueries.textile @@ -0,0 +1,33 @@ +h2. Model.action - Queries + +*==Query query = JPA.em().createQuery(“jpql_query”);==* +Access the persistence manager + +*==Post post = Post.findById(id);==* +*==List posts = Post.findAll();==* +Finder methods + +*==post.save();==* +Saves the object to the persistent store + +*==boolean post.validateAndSave();==* +true if object validates and saved, see validation annotations + +*==List posts = Post.all().from(50).fetch(100);==* +Read records 50 to 100, if any + +*==Post.find("select p from Post p, Comment c where c.post==* +*=== p and c.subject like ?", "%hop%");==* +Parametrized lookup using a join + +*==long userCount = Post.count("author=?", connectedUser);==* +*==long postCount = Post.count();==* +Counting records + +*==JPAPlugin.startTx(boolean readonly);==* +*==JPAPlugin.closeTx(boolean rollback);==* +Custom transaction control methods + +*==JPA.setRollbackOnly();==* +Forces a transaction rollback + diff --git a/documentation/cheatsheets/model/ch15-ModelBasics.textile b/documentation/cheatsheets/model/ch15-ModelBasics.textile new file mode 100644 index 0000000000..15bab21c9c --- /dev/null +++ b/documentation/cheatsheets/model/ch15-ModelBasics.textile @@ -0,0 +1,20 @@ +h2. Model - Basics + +*==@Entity(name=”sql_tbl”) public class Post extends Model==* +Specifies that the class is persistent + +*==@Embedded==* +Defines this field as being embedded + +*==@EmbeddedId==* +Defines this field as being (part of) the identity for the class, +and being embedded into this class + +*==@Embeddable==* +Specifies that the class is persistent embedded in another +persistent class + +*==@MappedSuperclass==* +Specifies that this class contains persistent information to be +mapped in a child + diff --git a/documentation/cheatsheets/model/ch16-ModelGenerators.textile b/documentation/cheatsheets/model/ch16-ModelGenerators.textile new file mode 100644 index 0000000000..8b22e8df30 --- /dev/null +++ b/documentation/cheatsheets/model/ch16-ModelGenerators.textile @@ -0,0 +1,14 @@ +h2. Model - Generators + +*==@GeneratedValue(strategy = [NONE, TABLE, SEQUENCE,==* +*==IDENTITY, AUTO])==* +Used to generate auto indexes + +*==@SequenceGenerator==* +Defines a generator of values using sequences in the +datastore for use with persistent entities + +*==@TableGenerator==* +Defines a generator of sequences using a table in the +datastore for use with persistent entities + diff --git a/documentation/cheatsheets/model/ch17-ModelRelationalMapping.textile b/documentation/cheatsheets/model/ch17-ModelRelationalMapping.textile new file mode 100644 index 0000000000..b43e879323 --- /dev/null +++ b/documentation/cheatsheets/model/ch17-ModelRelationalMapping.textile @@ -0,0 +1,33 @@ +h2. Model - Relational mapping + +*==@Table(name=”sql_tbl”, catalog=””, schema=””)==* +Defines the table where this class will be stored + +*==@Id==* +Defines this field as being (part of) the identity for the class + +*==@Version==* +Defines this field as storing the version for the class + +*==@Basic==* +Defines this field as being persistent, can be omitted + +*==@Transient==* +Defines this field as being transient (not persisted) + +*==@Lob(fetch=[LAZY, EAGER], type=[BLOB,CLOB])==* +Defines this field as being stored as a large object + +*==@UniqueConstraint(primary=false, String columns[])==* +Used to define secondary indexes + +*==@Temporal(DATE,TIME,TIMESTAMP)==* +Should only be used on java.util.Date and Calendar fields + +*==@Enumerated(ORDINAL, STRING)==* +Defines this field as storing an enumerated class + +*==@Column(name=”sql_column_name”)==* +Should the table column name be different from the field name + + diff --git a/documentation/cheatsheets/model/ch18-ModelCallbacks.textile b/documentation/cheatsheets/model/ch18-ModelCallbacks.textile new file mode 100644 index 0000000000..9a1dbdbdfb --- /dev/null +++ b/documentation/cheatsheets/model/ch18-ModelCallbacks.textile @@ -0,0 +1,25 @@ +h2. Model - Callbacks + +Convenient way to implement database independent trigers + +*==@PrePersist==* +Defines this method as being a callback for pre-persist events + +*==@PostPersist==* +Defines this method as being a callback for post-persist +events + +*==@PreRemove==* +Defines this method as being a callback for pre-remove events + +*==@PostRemove==* +Defines this method as being a callback for post-remove +events + +*==@PreUpdate==* +Defines this method as being a callback for pre-update +events + +*==@PostLoad==* +Defines this method as being a callback for post-load events + diff --git a/documentation/cheatsheets/model/ch19-ModelRelations.textile b/documentation/cheatsheets/model/ch19-ModelRelations.textile new file mode 100644 index 0000000000..2488f0be3e --- /dev/null +++ b/documentation/cheatsheets/model/ch19-ModelRelations.textile @@ -0,0 +1,29 @@ +h2. Model - Relations + +*==@OneToOne(entity, fetch=[LAZY,EAGER], nullable=true)==* +Defines this field as being a 1-1 relation with another +persistent entity + +*==@OneToMany(mappedBy="remote_attribute")==* +Defines this field as being a 1-N relation with other persistent +entities + +*==@ManyToMany(cascade=[ALL, PERSIST, MERGE,==* +*==REMOVE, REFRESH, DETACH])==* +Defines this field as being a M-N relation with other persistent +entities + +*==@ManyToOne==* +Defines this field as being a N-1 relation with another +persistent entity + +*==@JoinColumn(name = "id_connector")==* +Defines a column for joining to either a join table or foreign key +relation. + +*==@JoinTable(name = "nm_table", joinColumns ===* +*=={ @JoinColumn(name = "id_coupon", nullable = false) },==* +*==inverseJoinColumns = { @JoinColumn(name ===* +*=="id_campaign", nullable = false) })==* +Used to map ManyToMany relationships + diff --git a/documentation/cheatsheets/model/ch20-ModelJPAQueries.textile b/documentation/cheatsheets/model/ch20-ModelJPAQueries.textile new file mode 100644 index 0000000000..05354d642c --- /dev/null +++ b/documentation/cheatsheets/model/ch20-ModelJPAQueries.textile @@ -0,0 +1,13 @@ +h2. Model - JPA Queries + +*==@NamedQuery(name=”q1”, “jpql_query”);==* +Defines a named JPQL query to use in the persistence unit + +*==@NamedNativeQuery(name=”q2”,”sql_query”)==* +Defines a native SQL query for use in the persistence unit + +*==@SqlResultSetMapping==* +Used to map a native sql query result to the object model + +p(note). This is only a subset of the JPA2 annotations, hibernate also comes with its own non standard set + diff --git a/documentation/cheatsheets/multiEnvironment/ch26-MultiEnvironment.textile b/documentation/cheatsheets/multiEnvironment/ch26-MultiEnvironment.textile new file mode 100644 index 0000000000..ae843d99e8 --- /dev/null +++ b/documentation/cheatsheets/multiEnvironment/ch26-MultiEnvironment.textile @@ -0,0 +1,15 @@ +h2. Multi environment + +*==%test.db=mem==* +*==%test.jpa.ddl=create-drop==* +*==# Dev configuration==* +*==%dev.http.port=8080==* +*==%dev.application.log=DEBUG==* +*==%dev.application.mode=dev==* +*==# Production configuration==* +*==%prod.http.port=80==* +*==%prod.application.log=INFO==* +*==%prod.application.mode=prod==* +==play run --%prod or play run --%dev or play test== +Will pick the appropriate configurations + diff --git a/documentation/cheatsheets/templates/ch09-TemplateImplicitObjects.textile b/documentation/cheatsheets/templates/ch09-TemplateImplicitObjects.textile new file mode 100644 index 0000000000..232399355a --- /dev/null +++ b/documentation/cheatsheets/templates/ch09-TemplateImplicitObjects.textile @@ -0,0 +1,29 @@ +h2. Template - Implicit objects + +*errors* +The validation errors raised in the controller + +*flash* +Flash scope + +*lang* +The negotiated language + +*messages* +The messages map, i18 + +*out* +The output stream writer + +*params* +Current parameters + +*play* +Main framework class + +*request* +The current http request + +*session* +The session scope + diff --git a/documentation/cheatsheets/templates/ch10-TemplateTagGrammar.textile b/documentation/cheatsheets/templates/ch10-TemplateTagGrammar.textile new file mode 100644 index 0000000000..8e2e931dbc --- /dev/null +++ b/documentation/cheatsheets/templates/ch10-TemplateTagGrammar.textile @@ -0,0 +1,26 @@ +h2. Template - Tag grammar + +*==${ client.name }==* +Evaluates and outputs a variable + +*==${ client?.name }==* +Displays client.name only if client not null + +*==@{ Controller.action() }==* +Calculates url relative path to action + +*==@@{ Controller.action() }==* +Calculates url absolute path to action + +*==&{ message.key }==* +Message are maintained in conf/messages, supports i18 + +*==∗{ this is a comment }∗==* +What else to say? + +*==%{ out.print(“HelloWorld”) }%==* +Groovy scripts for UI logic + +*==#{ my.custom.tag /}==* +A typical custom tag - page context not shared + diff --git a/documentation/cheatsheets/templates/ch11-TemplateStandardTags.textile b/documentation/cheatsheets/templates/ch11-TemplateStandardTags.textile new file mode 100644 index 0000000000..a2a9a7afc7 --- /dev/null +++ b/documentation/cheatsheets/templates/ch11-TemplateStandardTags.textile @@ -0,0 +1,53 @@ +h2. Template - Standard Tags + +*==#{extends ʻpage.htmlʼ/}==* +*==#{doLayout /}==* +Master template decorators + +*==#{get 'title'}Used if title not set#{/get}==* +*==#{set title:ʻHome Pageʼ}==* +Shared variables between page and master templates + +*==#{include 'tree.html'/}==* +Includes fragment - page context is shared + +*==#{script id:'myscript' , src:ʻscript.js', charset:'utf-8' /}==* +*==#{stylesheet id:'main', media:'print', src:'print.css' /}==* +Imports script & styles in the page + +*==#{a @Application.logout() }Disconnect#{/a}==* +*==#{form @Client.create() , id:'form' enctype:'multipart/form-==* +*==data' } ... #{/form}==* +Handy tags to create anchors and forms + +*==#{verbatim}${'&'}#{/verbatim}==* +Disables HTML escaping + +*==#{i18n /}==* +Exports localized msgs in Javascript + +*==#{ifErrors} <p>Error(s) found!</p> #{/ifErrors}==* +Checks for validation errors + +*==#{ifError 'user.name'} #{error 'user.name' /} #{/ifError}==* +Checks a given error + +*==#{errors} <li>${error}</li> #{/errors}==* +Iterates over the current validation errors + +*==#{if cond}...#{/if}#{elseif cond}...#{/elseif}#{else}...#{/else}==* +*==#{ifnot cond}...#{/ifnot}==* +Conditional constructs + +*==#{list items:0..10, as:'i'}${i}#{/list}==* +*==#{list items:'a'..'z', as:'l'}${l} ${l_isLast ?'':'|' }#{/list}==* +*==#{list users}${_}#{/list}==* +Loop constructs + +*==#{list items:task, as:'task'}${task}#{/list}==* +*==#{else}No tasks on the list#{/else}==* +Tip: Else can be used along with list + +*==#{cache ʻkeyʼ, for:ʼ15minʼ}...#{/cache}==* +Caches content for 15 minutes + diff --git a/documentation/cheatsheets/templates/ch12-TemplateCustomTags.textile b/documentation/cheatsheets/templates/ch12-TemplateCustomTags.textile new file mode 100644 index 0000000000..7cbfd582f6 --- /dev/null +++ b/documentation/cheatsheets/templates/ch12-TemplateCustomTags.textile @@ -0,0 +1,9 @@ +h2. Template - Custom Tags + +*==@FastTags.Namespace("crionics")==* +*==public class RecaptchaTag extends FastTags {==* +public static void _recaptcha(Map args, Closure body, +PrintWriter out, ExecutableTemplate template, int fromLine) + +*==/app/view/tag/domain/mytag.tag==* +Custom tag can be called as {#domain.mytag/} \ No newline at end of file diff --git a/documentation/cheatsheets/templates/ch13-TemplateGroovyExtension.textile b/documentation/cheatsheets/templates/ch13-TemplateGroovyExtension.textile new file mode 100644 index 0000000000..36f85a0d44 --- /dev/null +++ b/documentation/cheatsheets/templates/ch13-TemplateGroovyExtension.textile @@ -0,0 +1,80 @@ +h2. Template - Groovy extension + +*==${ ['red', 'green', 'blue'].join('/') }==* +red/green/blue + +*==${ (["red", "green", "blue"] as String[]).add('pink').join(' ') }==* +red green blue pink + +*==${ (['red', 'green', 'blue'] as String[]).contains('green') }==* +true + +*==${(['red', 'gr', 'blue'] as String[]).remove('gr').join(' ')}==* +red blue + +*==${ ['red', 'green', 'blue'].last() }==* +blue + +*==${ new Date(new Date().getTime() - 1000000).since() }==* +16 minutes ago + +*==${new Date(1275910970000).format('dd MMMM yyyy==* +*==hh:mm:ss')}==* +07 June 2010 01:42:50 + +*==${ 1275910970000.asdate('dd MMMM yyyy hh:mm:ss') }==* +07 June 2010 01:42:50 + +*==${726016L.formatSize()}==* +709KB + +*==${ 42.formatCurrency('EUR').raw() }==* +€ 42.00 + +*==${ 42.page(10) }==* +5 + +*==journ${ ['cnn', 'c+', 'f2'].pluralize('al', 'aux') }==* +journaux + +*==${ "lorum ipsum dolor".capAll() }==* +Lorum Ipsum Dolor + +*==${ "lorum ipsum dolor".camelCase() }==* +LorumIpsumDolor + +*==${ "lorum ipsum dolor".capFirst() }==* +Lorum ipsum dolor + +*==${ "lorum ipsum dolor".cut('um') }==* +lor ips dolor + +*==${ "The <blink>tag</blink> is evil".escape().raw() }==* +The <blink>tag</blink> is evil + +*==${ "one\ntwo".nl2br() }==* +==one<br/>two== + +*==${ '<' } ${ '<'.raw() }==* +< < + +*==${ " (') (\") ".escapeJavaScript().raw() }==* +==(\') (\")== + +*==${ "".yesno('yes', 'no') }==* +no + +*==${ "not empty".yesno('yes', 'no') }==* +yes + +*==${"Stéphane Épardaud".noAccents()}==* +Stephane Epardaud + +*==${ "The Play! frameworkʼs manual".slugify() }==* +the-play-framework-s-manual + +*==${ "x".pad(4).raw() }==* +x    + + + diff --git a/documentation/cheatsheets/tests/ch21-TestUnitTests.textile b/documentation/cheatsheets/tests/ch21-TestUnitTests.textile new file mode 100644 index 0000000000..c69d3c80d6 --- /dev/null +++ b/documentation/cheatsheets/tests/ch21-TestUnitTests.textile @@ -0,0 +1,25 @@ +h2. Test - Unit Tests + +*==@Test public void getRental() { ... }==* +*==@Test (expected = NumberFormatException.class )==* +*==@Ignore==* +Ignore any errors + +*==@Test (timeout=400)==* +Test will fail after 400 milliseconds + +*==@Before public void prepareRecords();==* +Run before each unit test + +*==@After public void cleanupJunk()==* +Run after each unit test + +*==@BeforeClass void whenTestClassInstanciated();==* +Run once, when the test class gets instantiated + +*==@AfterClass void whenTestClassCompleted()==* +Run once when the test class is dismissed + +*==Assert.assert==* +There are tons of assertions, look it up + diff --git a/documentation/cheatsheets/tests/ch22-TestFunctionalTests.textile b/documentation/cheatsheets/tests/ch22-TestFunctionalTests.textile new file mode 100644 index 0000000000..fffd5253ef --- /dev/null +++ b/documentation/cheatsheets/tests/ch22-TestFunctionalTests.textile @@ -0,0 +1,17 @@ +h2. Test - Functional Tests + +*==public class ApplicationTest extends FunctionalTest==* +Functional test are unit tests with an http orientation + +*==newRequest()==* +*==newResponse()==* +*==GET(request, url)==* +*==PUT(request, url)==* +*==POST(request,url)==* +*==DELETE(request,url)==* +*==assertStatus(404, response)==* +*==assertHeaderEquals(headerName, value, response)==* +*==assertContentEquals(content, response)==* +*==assertContentType(type,response)==* +*==clearCookies()==* + diff --git a/documentation/cheatsheets/tests/ch23-TestSeleniumTests.textile b/documentation/cheatsheets/tests/ch23-TestSeleniumTests.textile new file mode 100644 index 0000000000..a8ff947a44 --- /dev/null +++ b/documentation/cheatsheets/tests/ch23-TestSeleniumTests.textile @@ -0,0 +1,14 @@ +h2. Test - Selenium Tests + +*==#{selenium}==* +clearSession() +open('/admin') +assertTextPresent('Login') +type('login', 'admin') +type('password', 'secret') +clickAndWait('signin') +// Verify that the user in correctly logged in +assertText('success', 'Welcome admin!') +*==#{/selenium}==* + + diff --git a/documentation/cheatsheets/tests/ch24-TestDataloader.textile b/documentation/cheatsheets/tests/ch24-TestDataloader.textile new file mode 100644 index 0000000000..c730eafa21 --- /dev/null +++ b/documentation/cheatsheets/tests/ch24-TestDataloader.textile @@ -0,0 +1,10 @@ +h2. Test - Data loader + +*==@Before public void setUp() { Fixtures.deleteAll();==* +*==Fixtures.load("data.yml");}==* +Fixtures is used to initialize the datastore ahead of a unit test + +*==#{fixture delete:'all', load:'data.yml' /}==* +*==#{selenium} ... #{/selenium}==* +Same idea using a selenium test + diff --git a/documentation/manual/home.textile b/documentation/manual/home.textile index 380349196a..59060eb2fd 100644 --- a/documentation/manual/home.textile +++ b/documentation/manual/home.textile @@ -18,6 +18,12 @@ Your first steps with Play and your first 5 minutes of fun. # "Your first application — the ‘Hello World’ tutorial":firstapp # "Sample applications":samples # "Live coding script - to practice, and impress your colleagues with":http://www.lunatech-research.fr/archives/2010/06/14/how-demo-play-framework-live-coding-script +# "Play framework cheat sheets - Controllers":cheatsheet/controllers +# "Play framework cheat sheets - Templates":cheatsheet/templates +# "Play framework cheat sheets - Model":cheatsheet/model +# "Play framework cheat sheets - Testing":cheatsheet/tests +# "Play framework cheat sheets - Multi Environment":cheatsheet/multiEnvironment +# "Play framework cheat sheets - Command Line":cheatsheet/commandLine h2. Tutorial -- Play guide, a real world app step-by-step diff --git a/modules/docviewer/app/DocViewerPlugin.java b/modules/docviewer/app/DocViewerPlugin.java index f0c27daeac..0b8feb52f8 100644 --- a/modules/docviewer/app/DocViewerPlugin.java +++ b/modules/docviewer/app/DocViewerPlugin.java @@ -44,6 +44,7 @@ public void onRoutesLoaded() { Router.prependRoute("GET", "/@documentation/files/{name}", "PlayDocumentation.file"); Router.prependRoute("GET", "/@documentation/modules/{module}/{id}", "PlayDocumentation.page"); Router.prependRoute("GET", "/@documentation/modules/{module}/images/{name}", "PlayDocumentation.image"); + Router.prependRoute("GET", "/@documentation/cheatsheet/{category}", "PlayDocumentation.cheatSheet"); } } diff --git a/modules/docviewer/app/controllers/PlayDocumentation.java b/modules/docviewer/app/controllers/PlayDocumentation.java index b2d10d7392..4be7ad617b 100644 --- a/modules/docviewer/app/controllers/PlayDocumentation.java +++ b/modules/docviewer/app/controllers/PlayDocumentation.java @@ -5,6 +5,8 @@ import play.libs.*; import play.vfs.*; +import helpers.CheatSheetHelper; + import java.io.*; import java.util.*; @@ -44,6 +46,23 @@ public static void page(String id, String module) throws Exception { render(id, html, title, modules, apis, module); } + public static void cheatSheet(String category) { + File[] sheetFiles = CheatSheetHelper.getSheets(category); + if(sheetFiles != null) { + List sheets = new ArrayList(); + + for (File file : sheetFiles) { + sheets.add(toHTML(IO.readContentAsString(file))); + } + + String title = CheatSheetHelper.getCategoryTitle(category); + Map otherCategories = CheatSheetHelper.listCategoriesAndTitles(); + + render(title, otherCategories, sheets); + } + notFound("Cheat sheet directory not found"); + } + public static void image(String name, String module) { File image = new File(Play.frameworkPath, "documentation/images/"+name+".png"); if(module != null) { @@ -63,8 +82,6 @@ public static void file(String name) { renderBinary(file); } - // - static String toHTML(String textile) { String html = new jj.play.org.eclipse.mylyn.wikitext.core.parser.MarkupParser(new jj.play.org.eclipse.mylyn.wikitext.textile.core.TextileLanguage()).parseToHtml(textile); html = html.substring(html.indexOf("") + 6, html.lastIndexOf("")); diff --git a/modules/docviewer/app/helpers/CheatSheetHelper.java b/modules/docviewer/app/helpers/CheatSheetHelper.java new file mode 100644 index 0000000000..7081a28138 --- /dev/null +++ b/modules/docviewer/app/helpers/CheatSheetHelper.java @@ -0,0 +1,89 @@ +package helpers; + +import java.io.File; +import java.io.FileFilter; +import java.util.Arrays; +import java.util.Comparator; +import java.util.LinkedHashMap; +import java.util.Map; + +import play.Play; + +public class CheatSheetHelper { + private static final File cheatSheetBaseDir = new File(Play.frameworkPath, "documentation/cheatsheets"); + + public static File[] getSheets(String category) { + File cheatSheetDir = new File(cheatSheetBaseDir, category); + + if(cheatSheetDir.exists() && cheatSheetDir.isDirectory()) { + File[] sheetFiles = cheatSheetDir.listFiles(new FileFilter() { + + @Override + public boolean accept(File pathname) { + return pathname.isFile() && pathname.getName().endsWith(".textile"); + } + }); + + // first letters of file name before "-" serves as sort index + Arrays.sort(sheetFiles, new Comparator() { + + @Override + public int compare(File f1, File f2) { + + String o1 = f1.getName(); + String o2 = f2.getName(); + + if (o1.contains("-") && o2.contains("-")) { + return o1.substring(0, o1.indexOf("-")) + .compareTo(o2.substring(0, o1.indexOf("-"))); + } else { + return o1.compareTo(o2); + } + } + }); + + return sheetFiles; + } + + return null; + } + + public static String getCategoryTitle(String category) { + // split camelCaseWord into separate words + String[] parts = category.trim().split("(? 0) { + title.append(Character.toUpperCase(part.charAt(0))); + + if (part.length() > 1) { + title.append(part.substring(1)); + } + title.append(" "); + } + } + + return title.toString().trim(); + } + + public static Map listCategoriesAndTitles() { + File[] categories = cheatSheetBaseDir.listFiles(new FileFilter() { + @Override + public boolean accept(File pathname) { + return pathname.isDirectory(); + } + }); + + Arrays.sort(categories); + + Map categoriesAndTitles = new LinkedHashMap(); + + for (File category : categories) { + categoriesAndTitles.put(category.getName(), getCategoryTitle(category.getName())); + } + + return categoriesAndTitles; + } +} diff --git a/modules/docviewer/app/views/PlayDocumentation/cheatSheet.html b/modules/docviewer/app/views/PlayDocumentation/cheatSheet.html new file mode 100644 index 0000000000..f13652d591 --- /dev/null +++ b/modules/docviewer/app/views/PlayDocumentation/cheatSheet.html @@ -0,0 +1,48 @@ + + + Play manual - Cheat Sheet + + + + + + +
+
+
+ Back to Table of contents +
+ +
+

${title}

+
+
+ #{list items: otherCategories, as: 'category'} + #{if category.value != title} + #{a @PlayDocumentation.cheatSheet(category.key)} + ${category.value} + #{/a} + #{/if} #{else} + ${category.value} + #{/else} +   + #{/list} +
+
+ +

Play ${play.version}

+
+
+
+ #{list items: sheets, as: 'sheet'} +
+ ${sheet.raw()} +
+ #{/list} +
+
+ + \ No newline at end of file diff --git a/modules/docviewer/public/playmanual/cheat-sheet.css b/modules/docviewer/public/playmanual/cheat-sheet.css new file mode 100644 index 0000000000..ecf90b3088 --- /dev/null +++ b/modules/docviewer/public/playmanual/cheat-sheet.css @@ -0,0 +1,92 @@ +.wikistyle .cs h2 { + margin-top: 0px !important; + margin-bottom: 1.5em !important; + border-top: 0px solid #e0e0e0 !important; + border-bottom: 4px solid #e0e0e0 !important; + padding-bottom: .5em !important; + padding-top: 0px !important; +} + +.cs-wrapper { + margin-left: 20px; + margin-right: 20px; +} + +div#content { + -moz-column-count: 3; + -moz-column-gap: 10px; + -webkit-column-count: 3; + -webkit-column-gap: 10px; + column-count: 3; + column-gap: 10px; + margin: auto; +} + +div.cs { + background-color: #fff; + font-size: 14px; + margin-top: 10px; + margin-bottom: 10px; + padding: 10px; + -webkit-box-shadow: #eee -1px 1px 2px; + -moz-box-shadow: #eee -1px 1px 2px; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} + +#docTopbar { + position: relative; + background: #fff; + padding: 10px; + height: 70px; + font-size: 12px; + overflow: hidden; + -webkit-box-shadow: #eee -1px 1px 2px; + -moz-box-shadow: #eee -1px 1px 2px; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} + +#docTopbar a { + color: #568C00; +} + +#docTopbar .titlebar { + width: 100%; + text-align: center; +} + +#backToToc { + font-size: 14px; + position: absolute; + top: 5px; + left: 5px; +} + +#backToToc span { + font-weight: bold; + color: #666; + font-size: 15px; +} + +#searchBar { + position: absolute; + bottom: 5px; + left: 5px; + height: 45px; +} + +#logobar { + right: 5px; + top: 5px; + text-align: center; + position: absolute; +} + +#logobar #version { + font-size: 10px; + margin-top: 0; + font-weight: normal; +} \ No newline at end of file