Seam SVN: r12264 - in modules/security/trunk/examples/seamspace: src and 13 other directories.
by seam-commits@lists.jboss.org
Author: shane.bryzak(a)jboss.com
Date: 2010-03-24 22:33:21 -0400 (Wed, 24 Mar 2010)
New Revision: 12264
Added:
modules/security/trunk/examples/seamspace/pom.xml
modules/security/trunk/examples/seamspace/src/
modules/security/trunk/examples/seamspace/src/main/
modules/security/trunk/examples/seamspace/src/main/java/
modules/security/trunk/examples/seamspace/src/main/java/org/
modules/security/trunk/examples/seamspace/src/main/java/org/jboss/
modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/
modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/
modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/
modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/
modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/AccountPermission.java
modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/AuthenticationEvents.java
modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/BlogAction.java
modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/BlogComment.java
modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/CommentAction.java
modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/ContentAction.java
modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/ContentServlet.java
modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/FriendAction.java
modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/FriendComment.java
modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/Hash.java
modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/HashGenerator.java
modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/ImagePermission.java
modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/Member.java
modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/MemberAccount.java
modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/MemberBlog.java
modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/MemberFriend.java
modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/MemberImage.java
modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/MemberRole.java
modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/PictureAction.java
modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/PictureSearch.java
modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/ProfileAction.java
modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/RegisterAction.java
modules/security/trunk/examples/seamspace/src/main/webapp/
modules/security/trunk/examples/seamspace/src/main/webapp/WEB-INF/
modules/security/trunk/examples/seamspace/src/main/webapp/WEB-INF/faces-config.xml
modules/security/trunk/examples/seamspace/src/main/webapp/WEB-INF/web.xml
modules/security/trunk/examples/seamspace/src/main/webapp/blog.xhtml
modules/security/trunk/examples/seamspace/src/main/webapp/blogentry.xhtml
modules/security/trunk/examples/seamspace/src/main/webapp/comment.xhtml
modules/security/trunk/examples/seamspace/src/main/webapp/createBlog.xhtml
modules/security/trunk/examples/seamspace/src/main/webapp/friendcomment.xhtml
modules/security/trunk/examples/seamspace/src/main/webapp/friendrequest.xhtml
modules/security/trunk/examples/seamspace/src/main/webapp/hashgen.xhtml
modules/security/trunk/examples/seamspace/src/main/webapp/home.xhtml
modules/security/trunk/examples/seamspace/src/main/webapp/imagepermissiondetail.page.xml
modules/security/trunk/examples/seamspace/src/main/webapp/imagepermissiondetail.xhtml
modules/security/trunk/examples/seamspace/src/main/webapp/imagepermissions.page.xml
modules/security/trunk/examples/seamspace/src/main/webapp/imagepermissions.xhtml
modules/security/trunk/examples/seamspace/src/main/webapp/images/
modules/security/trunk/examples/seamspace/src/main/webapp/images/bg_button.png
modules/security/trunk/examples/seamspace/src/main/webapp/images/checkmark.png
modules/security/trunk/examples/seamspace/src/main/webapp/images/cross.png
modules/security/trunk/examples/seamspace/src/main/webapp/images/ellipsis.png
modules/security/trunk/examples/seamspace/src/main/webapp/images/no_image.png
modules/security/trunk/examples/seamspace/src/main/webapp/index.html
modules/security/trunk/examples/seamspace/src/main/webapp/lightbox/
modules/security/trunk/examples/seamspace/src/main/webapp/lightbox/builder.js
modules/security/trunk/examples/seamspace/src/main/webapp/lightbox/bullet.gif
modules/security/trunk/examples/seamspace/src/main/webapp/lightbox/close.gif
modules/security/trunk/examples/seamspace/src/main/webapp/lightbox/closelabel.gif
modules/security/trunk/examples/seamspace/src/main/webapp/lightbox/effects.js
modules/security/trunk/examples/seamspace/src/main/webapp/lightbox/lightbox.css
modules/security/trunk/examples/seamspace/src/main/webapp/lightbox/lightbox.js
modules/security/trunk/examples/seamspace/src/main/webapp/lightbox/loading.gif
modules/security/trunk/examples/seamspace/src/main/webapp/lightbox/nextlabel.gif
modules/security/trunk/examples/seamspace/src/main/webapp/lightbox/prevlabel.gif
modules/security/trunk/examples/seamspace/src/main/webapp/lightbox/prototype.js
modules/security/trunk/examples/seamspace/src/main/webapp/lightbox/scriptaculous.js
modules/security/trunk/examples/seamspace/src/main/webapp/pictures.xhtml
modules/security/trunk/examples/seamspace/src/main/webapp/pictureupload.xhtml
modules/security/trunk/examples/seamspace/src/main/webapp/profile.xhtml
modules/security/trunk/examples/seamspace/src/main/webapp/register.xhtml
modules/security/trunk/examples/seamspace/src/main/webapp/register2.xhtml
modules/security/trunk/examples/seamspace/src/main/webapp/roledetail.page.xml
modules/security/trunk/examples/seamspace/src/main/webapp/roledetail.xhtml
modules/security/trunk/examples/seamspace/src/main/webapp/rolemanager.page.xml
modules/security/trunk/examples/seamspace/src/main/webapp/rolemanager.xhtml
modules/security/trunk/examples/seamspace/src/main/webapp/security.xhtml
modules/security/trunk/examples/seamspace/src/main/webapp/security_error.xhtml
modules/security/trunk/examples/seamspace/src/main/webapp/style/
modules/security/trunk/examples/seamspace/src/main/webapp/style/advertising.png
modules/security/trunk/examples/seamspace/src/main/webapp/style/btn_newpermission.png
modules/security/trunk/examples/seamspace/src/main/webapp/style/btn_newrole.png
modules/security/trunk/examples/seamspace/src/main/webapp/style/btn_newuser.png
modules/security/trunk/examples/seamspace/src/main/webapp/style/cal-next.png
modules/security/trunk/examples/seamspace/src/main/webapp/style/cal-prev.png
modules/security/trunk/examples/seamspace/src/main/webapp/style/date.css
modules/security/trunk/examples/seamspace/src/main/webapp/style/divider.png
modules/security/trunk/examples/seamspace/src/main/webapp/style/manage_roles.png
modules/security/trunk/examples/seamspace/src/main/webapp/style/manage_users.png
modules/security/trunk/examples/seamspace/src/main/webapp/style/padlock.png
modules/security/trunk/examples/seamspace/src/main/webapp/style/seamspace.css
modules/security/trunk/examples/seamspace/src/main/webapp/style/seamspace.png
modules/security/trunk/examples/seamspace/src/main/webapp/style/security.css
modules/security/trunk/examples/seamspace/src/main/webapp/style/table_header.png
modules/security/trunk/examples/seamspace/src/main/webapp/style/trash.png
modules/security/trunk/examples/seamspace/src/main/webapp/template.xhtml
modules/security/trunk/examples/seamspace/src/main/webapp/userdetail.page.xml
modules/security/trunk/examples/seamspace/src/main/webapp/userdetail.xhtml
modules/security/trunk/examples/seamspace/src/main/webapp/usermanager.page.xml
modules/security/trunk/examples/seamspace/src/main/webapp/usermanager.xhtml
modules/security/trunk/examples/seamspace/src/main/webapp/welcome.xhtml
Log:
add example source
Added: modules/security/trunk/examples/seamspace/pom.xml
===================================================================
--- modules/security/trunk/examples/seamspace/pom.xml (rev 0)
+++ modules/security/trunk/examples/seamspace/pom.xml 2010-03-25 02:33:21 UTC (rev 12264)
@@ -0,0 +1,77 @@
+<?xml version="1.0"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.jboss.seam.security</groupId>
+ <artifactId>seam-security-parent</artifactId>
+ <version>3.0.0-SNAPSHOT</version>
+ </parent>
+
+ <groupId>org.jboss.seam.security</groupId>
+ <artifactId>seam-security-seamspace-example</artifactId>
+ <packaging>war</packaging>
+ <version>3.0.0-SNAPSHOT</version>
+ <name>Seam Security SeamSpace Example</name>
+
+ <dependencies>
+ <!--dependency>
+ <groupId>org.testng</groupId>
+ <artifactId>testng</artifactId>
+ <scope>test</scope>
+ <classifier>jdk15</classifier>
+ </dependency-->
+
+ <dependency>
+ <groupId>javax.enterprise</groupId>
+ <artifactId>cdi-api</artifactId>
+ <scope>provided</scope>
+ <version>1.0</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.jboss.seam.security</groupId>
+ <artifactId>seam-security-core</artifactId>
+ <version>3.0.0-SNAPSHOT</version>
+ </dependency>
+
+ <dependency>
+ <groupId>javax.persistence</groupId>
+ <artifactId>persistence-api</artifactId>
+ <version>1.0</version>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>javax.transaction</groupId>
+ <artifactId>jta</artifactId>
+ <version>1.1</version>
+ <scope>provided</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>1.5</source>
+ <target>1.5</target>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-war-plugin</artifactId>
+ <version>2.0</version>
+ <configuration>
+ <warName>${pom.artifactId}</warName>
+ </configuration>
+ </plugin>
+
+ </plugins>
+ </build>
+
+</project>
+
Added: modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/AccountPermission.java
===================================================================
--- modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/AccountPermission.java (rev 0)
+++ modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/AccountPermission.java 2010-03-25 02:33:21 UTC (rev 12264)
@@ -0,0 +1,81 @@
+package org.jboss.seam.example.seamspace;
+
+import java.io.Serializable;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+
+import org.jboss.seam.annotations.security.permission.PermissionAction;
+import org.jboss.seam.annotations.security.permission.PermissionDiscriminator;
+import org.jboss.seam.annotations.security.permission.PermissionRole;
+import org.jboss.seam.annotations.security.permission.PermissionTarget;
+import org.jboss.seam.annotations.security.permission.PermissionUser;
+
+@Entity
+public class AccountPermission implements Serializable
+{
+ private static final long serialVersionUID = -5628863031792429938L;
+
+ private Integer permissionId;
+ private String recipient;
+ private String target;
+ private String action;
+ private String discriminator;
+
+ @Id @GeneratedValue
+ public Integer getPermissionId()
+ {
+ return permissionId;
+ }
+
+ public void setPermissionId(Integer permissionId)
+ {
+ this.permissionId = permissionId;
+ }
+
+ @PermissionUser
+ @PermissionRole
+ public String getRecipient()
+ {
+ return recipient;
+ }
+
+ public void setRecipient(String recipient)
+ {
+ this.recipient = recipient;
+ }
+
+ @PermissionTarget
+ public String getTarget()
+ {
+ return target;
+ }
+
+ public void setTarget(String target)
+ {
+ this.target = target;
+ }
+
+ @PermissionAction
+ public String getAction()
+ {
+ return action;
+ }
+
+ public void setAction(String action)
+ {
+ this.action = action;
+ }
+
+ @PermissionDiscriminator
+ public String getDiscriminator()
+ {
+ return discriminator;
+ }
+
+ public void setDiscriminator(String discriminator)
+ {
+ this.discriminator = discriminator;
+ }
+}
Added: modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/AuthenticationEvents.java
===================================================================
--- modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/AuthenticationEvents.java (rev 0)
+++ modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/AuthenticationEvents.java 2010-03-25 02:33:21 UTC (rev 12264)
@@ -0,0 +1,16 @@
+package org.jboss.seam.example.seamspace;
+
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Observer;
+import org.jboss.seam.contexts.Contexts;
+import org.jboss.seam.security.management.JpaIdentityStore;
+
+@Name("authenticationEvents")
+public class AuthenticationEvents
+{
+ @Observer(JpaIdentityStore.EVENT_USER_AUTHENTICATED)
+ public void loginSuccessful(MemberAccount account)
+ {
+ Contexts.getSessionContext().set("authenticatedMember", account.getMember());
+ }
+}
Added: modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/BlogAction.java
===================================================================
--- modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/BlogAction.java (rev 0)
+++ modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/BlogAction.java 2010-03-25 02:33:21 UTC (rev 12264)
@@ -0,0 +1,88 @@
+package org.jboss.seam.example.seamspace;
+
+import static org.jboss.seam.ScopeType.CONVERSATION;
+
+import java.util.ArrayList;
+import java.util.Date;
+
+import javax.persistence.EntityManager;
+import javax.persistence.NoResultException;
+
+import org.jboss.seam.annotations.Begin;
+import org.jboss.seam.annotations.End;
+import org.jboss.seam.annotations.Factory;
+import org.jboss.seam.annotations.In;
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Out;
+import org.jboss.seam.annotations.Scope;
+
+@Scope(CONVERSATION)
+@Name("blog")
+public class BlogAction
+{
+ private String name;
+ private Integer blogId;
+
+ @In
+ private EntityManager entityManager;
+
+ @In(required = false) @Out(required = false)
+ private MemberBlog selectedBlog;
+
+ @In(required = false)
+ private Member authenticatedMember;
+
+ /**
+ * Used to read a single blog entry for a member
+ */
+ @Factory("selectedBlog")
+ @Begin(join=true)
+ public void getBlog()
+ {
+ try
+ {
+ selectedBlog = (MemberBlog) entityManager.createQuery(
+ "from MemberBlog b where b.blogId = :blogId and b.member.memberName = :memberName")
+ .setParameter("blogId", blogId)
+ .setParameter("memberName", name)
+ .getSingleResult();
+ }
+ catch (NoResultException ex) { }
+ }
+
+ @Begin
+ public void createEntry()
+ {
+ selectedBlog = new MemberBlog();
+ }
+
+ @End
+ public void saveEntry()
+ {
+ selectedBlog.setMember(authenticatedMember);
+ selectedBlog.setEntryDate(new Date());
+ selectedBlog.setComments(new ArrayList<BlogComment>());
+
+ entityManager.persist(selectedBlog);
+ }
+
+ public String getName()
+ {
+ return name;
+ }
+
+ public void setName(String name)
+ {
+ this.name = name;
+ }
+
+ public Integer getBlogId()
+ {
+ return blogId;
+ }
+
+ public void setBlogId(Integer blogId)
+ {
+ this.blogId = blogId;
+ }
+}
Added: modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/BlogComment.java
===================================================================
--- modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/BlogComment.java (rev 0)
+++ modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/BlogComment.java 2010-03-25 02:33:21 UTC (rev 12264)
@@ -0,0 +1,94 @@
+package org.jboss.seam.example.seamspace;
+
+import java.io.Serializable;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Transient;
+
+import org.hibernate.validator.NotNull;
+import org.jboss.seam.annotations.Name;
+
+@Entity
+@Name("blogComment")
+public class BlogComment implements Serializable
+{
+ private static final long serialVersionUID = 5495139096911872039L;
+
+ private static SimpleDateFormat df = new SimpleDateFormat("EEEE, MMMM d, yyyy 'at' hh:mm a");
+
+ private Integer commentId;
+ private MemberBlog blog;
+ private Member commentor;
+ private Date commentDate;
+ private String comment;
+
+ @Id @GeneratedValue
+ public Integer getCommentId()
+ {
+ return commentId;
+ }
+
+ public void setCommentId(Integer commentId)
+ {
+ this.commentId = commentId;
+ }
+
+ @ManyToOne
+ @JoinColumn(name = "BLOG_ID")
+ public MemberBlog getBlog()
+ {
+ return blog;
+ }
+
+ public void setBlog(MemberBlog blog)
+ {
+ this.blog = blog;
+ }
+
+ @NotNull
+ public String getComment()
+ {
+ return comment;
+ }
+ public void setComment(String comment)
+ {
+ this.comment = comment;
+ }
+
+ @NotNull
+ public Date getCommentDate()
+ {
+ return commentDate;
+ }
+
+ public void setCommentDate(Date commentDate)
+ {
+ this.commentDate = commentDate;
+ }
+
+ @Transient
+ public String getFormattedCommentDate()
+ {
+ return df.format(commentDate);
+ }
+
+ @ManyToOne
+ @JoinColumn(name = "COMMENTOR_ID")
+ public Member getCommentor()
+ {
+ return commentor;
+ }
+
+ public void setCommentor(Member commentor)
+ {
+ this.commentor = commentor;
+ }
+
+
+}
Added: modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/CommentAction.java
===================================================================
--- modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/CommentAction.java (rev 0)
+++ modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/CommentAction.java 2010-03-25 02:33:21 UTC (rev 12264)
@@ -0,0 +1,55 @@
+package org.jboss.seam.example.seamspace;
+
+import static org.jboss.seam.ScopeType.CONVERSATION;
+
+import java.util.Date;
+
+import javax.persistence.EntityManager;
+
+import org.jboss.seam.annotations.Begin;
+import org.jboss.seam.annotations.In;
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Scope;
+import org.jboss.seam.annotations.Transactional;
+import org.jboss.seam.annotations.security.Insert;
+import org.jboss.seam.core.Conversation;
+
+@Scope(CONVERSATION)
+@Name("commentAction")
+@Transactional
+public class CommentAction
+{
+ @In
+ private EntityManager entityManager;
+
+ private BlogComment comment;
+
+ @In(required = false)
+ private Member authenticatedMember;
+
+ @In(required = false)
+ private MemberBlog selectedBlog;
+
+ @Begin(nested = true) @Insert(BlogComment.class)
+ public void createComment()
+ {
+ comment = new BlogComment();
+ comment.setCommentor(authenticatedMember);
+ comment.setBlog(selectedBlog);
+ }
+
+ public void saveComment()
+ {
+ comment.setCommentDate(new Date());
+ entityManager.persist(comment);
+
+ entityManager.refresh(selectedBlog);
+
+ Conversation.instance().end();
+ }
+
+ public BlogComment getComment()
+ {
+ return comment;
+ }
+}
Added: modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/ContentAction.java
===================================================================
--- modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/ContentAction.java (rev 0)
+++ modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/ContentAction.java 2010-03-25 02:33:21 UTC (rev 12264)
@@ -0,0 +1,27 @@
+package org.jboss.seam.example.seamspace;
+
+import static org.jboss.seam.ScopeType.STATELESS;
+
+import javax.persistence.EntityManager;
+
+import org.jboss.seam.annotations.In;
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Scope;
+import org.jboss.seam.security.Identity;
+
+@Scope(STATELESS)
+@Name("contentAction")
+public class ContentAction
+{
+ @In EntityManager entityManager;
+
+ public MemberImage getImage(int imageId)
+ {
+ MemberImage img = entityManager.find(MemberImage.class, imageId);
+
+ if (img == null || !Identity.instance().hasPermission(img, "view"))
+ return null;
+ else
+ return img;
+ }
+}
Added: modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/ContentServlet.java
===================================================================
--- modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/ContentServlet.java (rev 0)
+++ modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/ContentServlet.java 2010-03-25 02:33:21 UTC (rev 12264)
@@ -0,0 +1,137 @@
+package org.jboss.seam.example.seamspace;
+
+import java.awt.Graphics2D;
+import java.awt.RenderingHints;
+import java.awt.image.BufferedImage;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import javax.imageio.ImageIO;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.swing.ImageIcon;
+
+import org.jboss.seam.Component;
+
+/**
+ * Serves images and other member content
+ *
+ * @author Shane Bryzak
+ */
+public class ContentServlet extends HttpServlet
+{
+ private static final long serialVersionUID = -8461940507242022217L;
+
+ private static final String IMAGES_PATH = "/images";
+
+ /**
+ * The maximum width allowed for image rescaling
+ */
+ private static final int MAX_IMAGE_WIDTH = 1024;
+
+ private byte[] noImage;
+
+ public ContentServlet()
+ {
+ InputStream in = getClass().getResourceAsStream("/images/no_image.png");
+ if (in != null)
+ {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ byte[] buffer = new byte[512];
+ try
+ {
+ int read = in.read(buffer);
+ while (read != -1)
+ {
+ out.write(buffer, 0, read);
+ read = in.read(buffer);
+ }
+
+ noImage = out.toByteArray();
+ }
+ catch (IOException e) { }
+ }
+
+ }
+
+ @Override
+ protected void doGet(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException
+ {
+ if (IMAGES_PATH.equals(request.getPathInfo()))
+ {
+ ContentAction contentAction = (ContentAction) Component.getInstance(ContentAction.class);
+
+ String id = request.getParameter("id");
+ MemberImage mi = (id != null && !"".equals(id)) ?
+ contentAction.getImage(Integer.parseInt(id)) : null;
+
+ String contentType = null;
+ byte[] data = null;
+
+ if (mi != null && mi.getData() != null && mi.getData().length > 0)
+ {
+ contentType = mi.getContentType();
+ data = mi.getData();
+ }
+ else if (noImage != null)
+ {
+ contentType = "image/png";
+ data = noImage;
+ }
+
+ if (data != null)
+ {
+ response.setContentType(contentType);
+
+ boolean rescale = false;
+ int width = 0;
+ ImageIcon icon = null;
+
+ // Check if the image needs to be rescaled
+ if (request.getParameter("width") != null)
+ {
+ width = Math.min(MAX_IMAGE_WIDTH, Integer.parseInt(request
+ .getParameter("width")));
+ icon = new ImageIcon(data);
+ if (width > 0 && width != icon.getIconWidth())
+ rescale = true;
+ }
+
+ // Rescale the image if required
+ if (rescale)
+ {
+ double ratio = (double) width / icon.getIconWidth();
+ int height = (int) (icon.getIconHeight() * ratio);
+
+ int imageType = "image/png".equals(contentType) ?
+ BufferedImage.TYPE_INT_ARGB : BufferedImage.TYPE_INT_RGB;
+ BufferedImage bImg = new BufferedImage(width, height, imageType);
+ Graphics2D g2d = bImg.createGraphics();
+ g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
+ RenderingHints.VALUE_INTERPOLATION_BICUBIC);
+ g2d.drawImage(icon.getImage(), 0, 0, width, height, null);
+ g2d.dispose();
+
+ String formatName = "";
+ if (contentType != null && contentType.indexOf("png") != -1)
+ formatName = "png";
+ else if (contentType != null && (contentType.indexOf("jpg") != -1) ||
+ contentType.indexOf("jpeg") != -1)
+ formatName = "jpeg";
+
+ ImageIO.write(bImg, formatName, response.getOutputStream());
+ }
+ else
+ {
+ response.getOutputStream().write(data);
+ }
+ }
+
+ response.getOutputStream().flush();
+ }
+ }
+}
Added: modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/FriendAction.java
===================================================================
--- modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/FriendAction.java (rev 0)
+++ modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/FriendAction.java 2010-03-25 02:33:21 UTC (rev 12264)
@@ -0,0 +1,109 @@
+package org.jboss.seam.example.seamspace;
+
+import static org.jboss.seam.ScopeType.CONVERSATION;
+
+import java.io.Serializable;
+import java.util.Date;
+
+import javax.ejb.Remove;
+import javax.persistence.EntityManager;
+import javax.persistence.NoResultException;
+
+import org.jboss.seam.annotations.Begin;
+import org.jboss.seam.annotations.Destroy;
+import org.jboss.seam.annotations.End;
+import org.jboss.seam.annotations.Factory;
+import org.jboss.seam.annotations.In;
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Out;
+import org.jboss.seam.annotations.Scope;
+import org.jboss.seam.annotations.web.RequestParameter;
+import org.jboss.seam.contexts.Contexts;
+import org.jboss.seam.faces.FacesMessages;
+import org.jboss.seam.security.Identity;
+
+@Scope(CONVERSATION)
+@Name("friendAction")
+public class FriendAction implements Serializable
+{
+ private static final long serialVersionUID = 4565339001481077911L;
+
+ @RequestParameter("name")
+ private String name;
+
+ @Out(required = false)
+ private FriendComment friendComment;
+
+ @Out(required = false)
+ private MemberFriend friendRequest;
+
+ @In(required = false)
+ private Member authenticatedMember;
+
+ @In
+ private EntityManager entityManager;
+
+ @Factory("friendComment") @Begin
+ public void createComment()
+ {
+ try
+ {
+ Member member = (Member) entityManager.createQuery(
+ "from Member where memberName = :memberName")
+ .setParameter("memberName", name)
+ .getSingleResult();
+
+ Contexts.getMethodContext().set("friends", member.getFriends());
+ Identity.instance().checkPermission(member, "createFriendComment");
+
+ friendComment = new FriendComment();
+ friendComment.setFriend(authenticatedMember);
+ friendComment.setMember(member);
+ }
+ catch (NoResultException ex)
+ {
+ FacesMessages.instance().add("Member not found.");
+ }
+ }
+
+ @End
+ public void saveComment()
+ {
+ friendComment.setCommentDate(new Date());
+ entityManager.persist(friendComment);
+ }
+
+ @Begin
+ public void createRequest()
+ {
+ try
+ {
+ Member member = (Member) entityManager.createQuery(
+ "from Member where memberName = :memberName")
+ .setParameter("memberName", name)
+ .getSingleResult();
+
+ Contexts.getMethodContext().set("friends", member.getFriends());
+ Identity.instance().checkPermission(member, "createFriendRequest");
+
+ friendRequest = new MemberFriend();
+ friendRequest.setFriend(authenticatedMember);
+ friendRequest.setMember(member);
+ }
+ catch (NoResultException ex)
+ {
+ FacesMessages.instance().add("Member not found.");
+ }
+ }
+
+ @End
+ public void saveRequest()
+ {
+ friendRequest.getMember().getFriends().add(friendRequest);
+ entityManager.persist(friendRequest);
+ FacesMessages.instance().add("Friend request sent");
+ }
+
+ @Remove @Destroy
+ public void destroy() { }
+}
Added: modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/FriendComment.java
===================================================================
--- modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/FriendComment.java (rev 0)
+++ modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/FriendComment.java 2010-03-25 02:33:21 UTC (rev 12264)
@@ -0,0 +1,91 @@
+package org.jboss.seam.example.seamspace;
+
+import java.io.Serializable;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Transient;
+
+import org.jboss.seam.annotations.Name;
+
+@Entity
+@Name("friendComment")
+public class FriendComment implements Serializable
+{
+ private static final long serialVersionUID = -288494386341008371L;
+
+ private static SimpleDateFormat df = new SimpleDateFormat("d MMMM yyyy hh:mm a");
+
+ private Integer id;
+ private Member member;
+ private Member friend;
+ private Date commentDate;
+ private String comment;
+
+ @Id @GeneratedValue
+ public Integer getId()
+ {
+ return id;
+ }
+
+ public void setId(Integer id)
+ {
+ this.id = id;
+ }
+
+ public String getComment()
+ {
+ return comment;
+ }
+
+ public void setComment(String comment)
+ {
+ this.comment = comment;
+ }
+
+ public Date getCommentDate()
+ {
+ return commentDate;
+ }
+
+ public void setCommentDate(Date commentDate)
+ {
+ this.commentDate = commentDate;
+ }
+
+ @Transient
+ public String getFormattedCommentDate()
+ {
+ return df.format(commentDate);
+ }
+
+ @ManyToOne
+ @JoinColumn(name = "FRIEND_ID")
+ public Member getFriend()
+ {
+ return friend;
+ }
+
+ public void setFriend(Member friend)
+ {
+ this.friend = friend;
+ }
+
+ @ManyToOne
+ @JoinColumn(name = "MEMBER_ID")
+ public Member getMember()
+ {
+ return member;
+ }
+
+ public void setMember(Member member)
+ {
+ this.member = member;
+ }
+
+}
Added: modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/Hash.java
===================================================================
--- modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/Hash.java (rev 0)
+++ modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/Hash.java 2010-03-25 02:33:21 UTC (rev 12264)
@@ -0,0 +1,45 @@
+package org.jboss.seam.example.seamspace;
+
+import java.security.MessageDigest;
+
+import org.jboss.seam.Component;
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.util.Hex;
+
+@Name("hash")
+public class Hash {
+ String hashFunction = "MD5";
+ String charset = "UTF-8";
+
+ public String hash(String password) {
+ try {
+ MessageDigest md = MessageDigest.getInstance(hashFunction);
+ md.update(password.getBytes(charset));
+ byte[] raw = md.digest();
+ return new String(Hex.encodeHex(raw));
+ }
+ catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public String getCharset() {
+ return charset;
+ }
+
+ public void setCharset(String charset) {
+ this.charset = charset;
+ }
+
+ public String getHashFunction() {
+ return hashFunction;
+ }
+
+ public void setHashFunction(String hashFunction) {
+ this.hashFunction = hashFunction;
+ }
+
+ public static Hash instance() {
+ return (Hash) Component.getInstance(Hash.class);
+ }
+}
Added: modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/HashGenerator.java
===================================================================
--- modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/HashGenerator.java (rev 0)
+++ modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/HashGenerator.java 2010-03-25 02:33:21 UTC (rev 12264)
@@ -0,0 +1,78 @@
+package org.jboss.seam.example.seamspace;
+
+import org.jboss.seam.ScopeType;
+import org.jboss.seam.annotations.In;
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Scope;
+import org.jboss.seam.security.crypto.BinTools;
+import org.jboss.seam.security.management.JpaIdentityStore;
+import org.jboss.seam.security.management.PasswordHash;
+
+(a)Scope(ScopeType.EVENT)
+@Name("hashgenerator")
+public class HashGenerator
+{
+ @In JpaIdentityStore identityStore;
+
+ private String password;
+ private String passwordHash;
+ private String passwordSalt;
+
+ public String getPassword()
+ {
+ return password;
+ }
+
+ public void setPassword(String password)
+ {
+ this.password = password;
+ }
+
+ public String getPasswordHash()
+ {
+ return passwordHash;
+ }
+
+ public void setPasswordHash(String passwordHash)
+ {
+ this.passwordHash = passwordHash;
+ }
+
+ public String getPasswordSalt()
+ {
+ return passwordSalt;
+ }
+
+ public void setPasswordSalt(String passwordSalt)
+ {
+ this.passwordSalt = passwordSalt;
+ }
+
+ public void generate()
+ {
+ byte[] salt;
+
+ if (passwordSalt == null || "".equals(passwordSalt.trim()))
+ {
+ salt = PasswordHash.instance().generateRandomSalt();
+ passwordSalt = BinTools.bin2hex(salt);
+ }
+ else
+ {
+ salt = BinTools.hex2bin(passwordSalt);
+ }
+
+ passwordHash = identityStore.generatePasswordHash(password, salt);
+ }
+
+ public String getSql()
+ {
+ StringBuilder sb = new StringBuilder();
+ sb.append("INSERT INTO USER_ACCOUNT (username, password_hash, password_salt) values ('johnsmith', '");
+ sb.append(passwordHash);
+ sb.append("', '");
+ sb.append(passwordSalt);
+ sb.append("');");
+ return sb.toString();
+ }
+}
Added: modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/ImagePermission.java
===================================================================
--- modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/ImagePermission.java (rev 0)
+++ modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/ImagePermission.java 2010-03-25 02:33:21 UTC (rev 12264)
@@ -0,0 +1,200 @@
+package org.jboss.seam.example.seamspace;
+
+import static org.jboss.seam.ScopeType.CONVERSATION;
+
+import java.io.Serializable;
+import java.security.Principal;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.persistence.EntityManager;
+
+import org.jboss.seam.annotations.Begin;
+import org.jboss.seam.annotations.In;
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Scope;
+import org.jboss.seam.core.Conversation;
+import org.jboss.seam.faces.FacesMessages;
+import org.jboss.seam.security.Role;
+import org.jboss.seam.security.SimplePrincipal;
+import org.jboss.seam.security.management.IdentityManager;
+import org.jboss.seam.security.permission.Permission;
+import org.jboss.seam.security.permission.PermissionManager;
+import org.jboss.seam.security.permission.action.PermissionSearch;
+
+@Name("imagePermission")
+@Scope(CONVERSATION)
+public class ImagePermission implements Serializable
+{
+ private static final long serialVersionUID = -4943654157860780587L;
+
+ private List<String> selectedRoles;
+ private List<Member> selectedFriends;
+ private List<String> selectedActions;
+
+ private List<String> originalActions;
+
+ private List<Member> availableFriends;
+
+ @In IdentityManager identityManager;
+ @In PermissionManager permissionManager;
+
+ @In EntityManager entityManager;
+
+ @In PermissionSearch permissionSearch;
+
+ private MemberImage target;
+
+ private Principal recipient;
+
+ @SuppressWarnings("unchecked")
+ @Begin(nested = true)
+ public void createPermission()
+ {
+ target = (MemberImage) permissionSearch.getTarget();
+
+ selectedFriends = new ArrayList<Member>();
+
+ availableFriends = entityManager.createQuery(
+ "select f.friend from MemberFriend f where f.member = :member and f.authorized = true")
+ .setParameter("member", target.getMember())
+ .getResultList();
+ }
+
+ @Begin(nested = true)
+ public void editPermission()
+ {
+ target = (MemberImage) permissionSearch.getTarget();
+ recipient = permissionSearch.getSelectedRecipient();
+
+ List<Permission> permissions = permissionManager.listPermissions(target);
+
+ selectedActions = new ArrayList<String>();
+
+ for (Permission permission : permissions)
+ {
+ if (permission.getRecipient().equals(recipient))
+ {
+ if (!selectedActions.contains(permission.getAction()))
+ {
+ selectedActions.add(permission.getAction());
+ }
+ }
+ }
+
+ originalActions = new ArrayList<String>(selectedActions);
+ }
+
+ public List<String> getSelectedRoles()
+ {
+ return selectedRoles;
+ }
+
+ public void setSelectedRoles(List<String> selectedRoles)
+ {
+ this.selectedRoles = selectedRoles;
+ }
+
+ public List<Member> getSelectedFriends()
+ {
+ return selectedFriends;
+ }
+
+ public void setSelectedFriends(List<Member> selectedFriends)
+ {
+ this.selectedFriends = selectedFriends;
+ }
+
+ public List<String> getSelectedActions()
+ {
+ return selectedActions;
+ }
+
+ public void setSelectedActions(List<String> selectedActions)
+ {
+ this.selectedActions = selectedActions;
+ }
+
+ public String applyPermissions()
+ {
+ // If the recipient isn't null, it means we're editing existing permissions
+ if (recipient != null)
+ {
+ List<Permission> grantedPermissions = new ArrayList<Permission>();
+ List<Permission> revokedPermissions = new ArrayList<Permission>();
+
+ for (String action : selectedActions)
+ {
+ if (!originalActions.contains(action))
+ {
+ grantedPermissions.add(new Permission(target, action, recipient));
+ }
+ }
+
+ for (String action : originalActions)
+ {
+ if (!selectedActions.contains(action))
+ {
+ revokedPermissions.add(new Permission(target, action, recipient));
+ }
+ }
+
+ if (!grantedPermissions.isEmpty()) permissionManager.grantPermissions(grantedPermissions);
+ if (!revokedPermissions.isEmpty()) permissionManager.revokePermissions(revokedPermissions);
+ }
+ // otherwise this is a set of new permissions
+ else
+ {
+ if (selectedActions.size() == 0)
+ {
+ FacesMessages.instance().add("You must select at least one action");
+ return "failure";
+ }
+
+ List<Permission> permissions = new ArrayList<Permission>();
+
+ for (String role : selectedRoles)
+ {
+ Principal r = new Role(role);
+ for (String action : selectedActions)
+ {
+ permissions.add(new Permission(target, action, r));
+ }
+ }
+
+ for (Member friend : selectedFriends)
+ {
+ MemberAccount acct = (MemberAccount) entityManager.createQuery(
+ "select a from MemberAccount a where a.member = :member")
+ .setParameter("member", friend)
+ .getSingleResult();
+
+ Principal p = new SimplePrincipal(acct.getUsername());
+
+ for (String action : selectedActions)
+ {
+ permissions.add(new Permission(target, action, p));
+ }
+ }
+
+ permissionManager.grantPermissions(permissions);
+ }
+ Conversation.instance().endBeforeRedirect();
+ return "success";
+ }
+
+ public List<Member> getAvailableFriends()
+ {
+ return availableFriends;
+ }
+
+ public MemberImage getTarget()
+ {
+ return target;
+ }
+
+ public Principal getRecipient()
+ {
+ return recipient;
+ }
+}
Added: modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/Member.java
===================================================================
--- modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/Member.java (rev 0)
+++ modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/Member.java 2010-03-25 02:33:21 UTC (rev 12264)
@@ -0,0 +1,252 @@
+package org.jboss.seam.example.seamspace;
+
+import java.io.Serializable;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.Set;
+
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.OneToMany;
+import javax.persistence.OneToOne;
+import javax.persistence.Table;
+import javax.persistence.Transient;
+import javax.persistence.UniqueConstraint;
+
+import org.hibernate.validator.Email;
+import org.hibernate.validator.Length;
+import org.hibernate.validator.NotNull;
+import org.hibernate.validator.Pattern;
+import org.jboss.seam.annotations.Name;
+
+/**
+ * A member account
+ *
+ * @author Shane Bryzak
+ */
+@Entity
+@Name("member")
+@Table(uniqueConstraints = @UniqueConstraint(columnNames = "membername"))
+public class Member implements Serializable
+{
+ private static final long serialVersionUID = 5179242727836683375L;
+
+ public enum Gender {
+ male("Male", "his"),
+ female("Female", "her");
+
+ private String descr;
+ private String possessive;
+
+ Gender(String descr, String possessive) {
+ this.descr = descr;
+ this.possessive = possessive;
+ }
+ public String getDescr() {
+ return descr;
+ }
+
+ public String getPossessive() {
+ return possessive;
+ }
+ };
+
+ private Integer memberId;
+ private String memberName;
+ private String firstName;
+ private String lastName;
+ private String email;
+ private MemberImage picture;
+
+ private String tagline;
+ private Gender gender;
+ private Date dob;
+ private String location;
+ private Date memberSince;
+
+ private Set<MemberImage> images;
+ private Set<MemberFriend> friends;
+
+ @Id @GeneratedValue
+ public Integer getMemberId()
+ {
+ return memberId;
+ }
+
+ public void setMemberId(Integer memberId)
+ {
+ this.memberId = memberId;
+ }
+
+ @NotNull
+ @Length(min = 3, max = 40)
+ @Pattern(regex="[a-zA-Z]?[a-zA-Z0-9_]+",
+ message="Member name must start with a letter, and only contain letters, numbers or underscores")
+ public String getMemberName()
+ {
+ return memberName;
+ }
+
+ public void setMemberName(String memberName)
+ {
+ this.memberName = memberName;
+ }
+
+ @NotNull
+ @Length(min = 3, max = 40)
+ @Pattern(regex="[a-zA-Z]+", message="First name must only contain letters")
+ public String getFirstName()
+ {
+ return firstName;
+ }
+
+ public void setFirstName(String firstName)
+ {
+ this.firstName = firstName;
+ }
+
+ @NotNull
+ @Length(min = 3, max = 40)
+ @Pattern(regex="[a-zA-Z]+", message="Last name must only contain letters")
+ public String getLastName()
+ {
+ return lastName;
+ }
+
+ public void setLastName(String lastName)
+ {
+ this.lastName = lastName;
+ }
+
+ @NotNull @Email
+ public String getEmail()
+ {
+ return email;
+ }
+
+ public void setEmail(String email)
+ {
+ this.email = email;
+ }
+
+ @OneToOne(fetch = FetchType.LAZY)
+ @JoinColumn(name = "PICTURE_ID")
+ public MemberImage getPicture()
+ {
+ return picture;
+ }
+
+ public void setPicture(MemberImage picture)
+ {
+ this.picture = picture;
+ }
+
+ @NotNull
+ public Date getDob()
+ {
+ return dob;
+ }
+
+ public void setDob(Date dob)
+ {
+ this.dob = dob;
+ }
+
+ @NotNull
+ public Gender getGender()
+ {
+ return gender;
+ }
+
+ public void setGender(Gender gender)
+ {
+ this.gender = gender;
+ }
+
+ public String getLocation()
+ {
+ return location;
+ }
+
+ public void setLocation(String location)
+ {
+ this.location = location;
+ }
+
+ @NotNull
+ public Date getMemberSince()
+ {
+ return memberSince;
+ }
+
+ public void setMemberSince(Date memberSince)
+ {
+ this.memberSince = memberSince;
+ }
+
+ public String getTagline()
+ {
+ return tagline;
+ }
+
+ public void setTagline(String tagline)
+ {
+ this.tagline = tagline;
+ }
+
+ @OneToMany(mappedBy = "member", fetch = FetchType.LAZY)
+ public Set<MemberImage> getImages()
+ {
+ return images;
+ }
+
+ public void setImages(Set<MemberImage> images)
+ {
+ this.images = images;
+ }
+
+ @OneToMany(mappedBy = "member")
+ public Set<MemberFriend> getFriends()
+ {
+ return friends;
+ }
+
+ public void setFriends(Set<MemberFriend> friends)
+ {
+ this.friends = friends;
+ }
+
+ @Transient
+ public boolean isFriend(Member member)
+ {
+ for (MemberFriend f : friends)
+ {
+ if (f.getFriend().getMemberId().equals(member.getMemberId())) return true;
+ }
+
+ return false;
+ }
+
+ @Transient
+ public String getAge()
+ {
+ Calendar birthday = new GregorianCalendar();
+ birthday.setTime(dob);
+ int by = birthday.get(Calendar.YEAR);
+ int bm = birthday.get(Calendar.MONTH);
+ int bd = birthday.get(Calendar.DATE);
+
+ Calendar now = new GregorianCalendar();
+ now.setTimeInMillis(System.currentTimeMillis());
+ int ny = now.get(Calendar.YEAR);
+ int nm = now.get(Calendar.MONTH);
+ int nd = now.get(Calendar.DATE);
+
+ int age = ny - by + (nm > bm || (nm == bm && nd >= bd) ? 0 : -1);
+ return String.format("%d years old", age);
+ }
+}
Added: modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/MemberAccount.java
===================================================================
--- modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/MemberAccount.java (rev 0)
+++ modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/MemberAccount.java 2010-03-25 02:33:21 UTC (rev 12264)
@@ -0,0 +1,120 @@
+package org.jboss.seam.example.seamspace;
+
+import java.io.Serializable;
+import java.util.Set;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.JoinTable;
+import javax.persistence.ManyToMany;
+import javax.persistence.OneToOne;
+import javax.persistence.Table;
+import javax.persistence.UniqueConstraint;
+
+import org.hibernate.validator.NotNull;
+import org.jboss.seam.annotations.security.management.PasswordSalt;
+import org.jboss.seam.annotations.security.management.UserEnabled;
+import org.jboss.seam.annotations.security.management.UserPassword;
+import org.jboss.seam.annotations.security.management.UserPrincipal;
+import org.jboss.seam.annotations.security.management.UserRoles;
+
+@Entity
+@Table(uniqueConstraints = @UniqueConstraint(columnNames = "username"))
+public class MemberAccount implements Serializable
+{
+ private static final long serialVersionUID = 6368734442192368866L;
+
+ private Integer accountId;
+ private String username;
+ private String passwordHash;
+ private String passwordSalt;
+ private boolean enabled;
+
+ private Set<MemberRole> roles;
+ private Member member;
+
+ @Id @GeneratedValue
+ public Integer getAccountId()
+ {
+ return accountId;
+ }
+
+ public void setAccountId(Integer accountId)
+ {
+ this.accountId = accountId;
+ }
+
+ @NotNull @UserPrincipal
+ public String getUsername()
+ {
+ return username;
+ }
+
+ public void setUsername(String username)
+ {
+ this.username = username;
+ }
+
+ @UserPassword
+ public String getPasswordHash()
+ {
+ return passwordHash;
+ }
+
+ public void setPasswordHash(String passwordHash)
+ {
+ this.passwordHash = passwordHash;
+ }
+
+ @PasswordSalt
+ public String getPasswordSalt()
+ {
+ return passwordSalt;
+ }
+
+ public void setPasswordSalt(String passwordSalt)
+ {
+ this.passwordSalt = passwordSalt;
+ }
+
+ @UserEnabled
+ public boolean isEnabled()
+ {
+ return enabled;
+ }
+
+ public void setEnabled(boolean enabled)
+ {
+ this.enabled = enabled;
+ }
+
+ @UserRoles
+ @ManyToMany(targetEntity = MemberRole.class)
+ @JoinTable(name = "AccountMembership",
+ joinColumns = @JoinColumn(name = "AccountId"),
+ inverseJoinColumns = @JoinColumn(name = "MemberOf")
+ )
+ public Set<MemberRole> getRoles()
+ {
+ return roles;
+ }
+
+ public void setRoles(Set<MemberRole> roles)
+ {
+ this.roles = roles;
+ }
+
+ @OneToOne
+ @JoinColumn(name = "MEMBER_ID")
+ public Member getMember()
+ {
+ return member;
+ }
+
+ public void setMember(Member member)
+ {
+ this.member = member;
+ }
+}
Added: modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/MemberBlog.java
===================================================================
--- modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/MemberBlog.java (rev 0)
+++ modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/MemberBlog.java 2010-03-25 02:33:21 UTC (rev 12264)
@@ -0,0 +1,134 @@
+package org.jboss.seam.example.seamspace;
+
+import java.io.Serializable;
+import java.text.SimpleDateFormat;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.List;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.OneToMany;
+import javax.persistence.PrePersist;
+import javax.persistence.Transient;
+
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.security.Restrict;
+
+@Entity
+@Name("memberBlog")
+public class MemberBlog implements Serializable
+{
+ private static final long serialVersionUID = 7824113911888715595L;
+
+ private static SimpleDateFormat df = new SimpleDateFormat("EEEE, MMMM d, yyyy - hh:mm a");
+
+ private Integer blogId;
+ private Member member;
+ private Date entryDate;
+ private String title;
+ private String text;
+
+ private List<BlogComment> comments;
+
+ /**
+ * This is an example of a security restriction. Any attempts to persist a
+ * new memberBlog instance requires the user to pass a permission check. In
+ * this case, because the method is annotated with <code>@PrePersist</code>
+ * the required permission is memberBlog:insert
+ */
+ @PrePersist @Restrict
+ public void prePersist() {}
+
+ @Id @GeneratedValue
+ public Integer getBlogId()
+ {
+ return blogId;
+ }
+
+ public void setBlogId(Integer blogId)
+ {
+ this.blogId = blogId;
+ }
+
+ public Date getEntryDate()
+ {
+ return entryDate;
+ }
+
+ public void setEntryDate(Date entryDate)
+ {
+ this.entryDate = entryDate;
+ }
+
+ @Transient
+ public String getFormattedEntryDate()
+ {
+ return df.format(entryDate);
+ }
+
+ @ManyToOne
+ @JoinColumn(name = "MEMBER_ID")
+ public Member getMember()
+ {
+ return member;
+ }
+
+ public void setMember(Member member)
+ {
+ this.member = member;
+ }
+
+ public String getText()
+ {
+ return text;
+ }
+
+ public void setText(String text)
+ {
+ this.text = text;
+ }
+
+ public String getTitle()
+ {
+ return title;
+ }
+
+ public void setTitle(String title)
+ {
+ this.title = title;
+ }
+
+ @OneToMany(mappedBy = "blog")
+ public List<BlogComment> getComments()
+ {
+ return comments;
+ }
+
+ public void setComments(List<BlogComment> comments)
+ {
+ this.comments = comments;
+ }
+
+ @Transient
+ public List<BlogComment> getSortedComments()
+ {
+ Collections.sort(comments, new Comparator<BlogComment>() {
+ public int compare(BlogComment o1, BlogComment o2) {
+ return (int) (o1.getCommentDate().getTime() - o2.getCommentDate().getTime());
+ }
+ });
+
+ return comments;
+ }
+
+ @Transient
+ public int getCommentCount()
+ {
+ return comments.size();
+ }
+}
Added: modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/MemberFriend.java
===================================================================
--- modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/MemberFriend.java (rev 0)
+++ modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/MemberFriend.java 2010-03-25 02:33:21 UTC (rev 12264)
@@ -0,0 +1,92 @@
+package org.jboss.seam.example.seamspace;
+
+import java.io.Serializable;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+
+import org.jboss.seam.annotations.Name;
+
+@Entity
+@Name("memberFriend")
+public class MemberFriend implements Serializable
+{
+ private static final long serialVersionUID = -167586088947004386L;
+
+ private Integer id;
+ private Member member;
+ private Member friend;
+
+ private String introduction;
+ private String response;
+
+ private boolean authorized;
+
+ @Id @GeneratedValue
+ public Integer getId()
+ {
+ return id;
+ }
+
+ public void setId(Integer id)
+ {
+ this.id = id;
+ }
+
+ public boolean isAuthorized()
+ {
+ return authorized;
+ }
+
+ public void setAuthorized(boolean authorized)
+ {
+ this.authorized = authorized;
+ }
+
+ @ManyToOne
+ @JoinColumn(name = "FRIEND_ID")
+ public Member getFriend()
+ {
+ return friend;
+ }
+
+ public void setFriend(Member friend)
+ {
+ this.friend = friend;
+ }
+
+ @ManyToOne
+ @JoinColumn(name = "MEMBER_ID")
+ public Member getMember()
+ {
+ return member;
+ }
+
+ public void setMember(Member member)
+ {
+ this.member = member;
+ }
+
+ public String getIntroduction()
+ {
+ return introduction;
+ }
+
+ public void setIntroduction(String introduction)
+ {
+ this.introduction = introduction;
+ }
+
+ public String getResponse()
+ {
+ return response;
+ }
+
+ public void setResponse(String response)
+ {
+ this.response = response;
+ }
+}
Added: modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/MemberImage.java
===================================================================
--- modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/MemberImage.java (rev 0)
+++ modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/MemberImage.java 2010-03-25 02:33:21 UTC (rev 12264)
@@ -0,0 +1,84 @@
+package org.jboss.seam.example.seamspace;
+
+import java.io.Serializable;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.Lob;
+import javax.persistence.ManyToOne;
+
+import org.jboss.seam.annotations.security.permission.Permission;
+import org.jboss.seam.annotations.security.permission.Permissions;
+
+@Permissions({
+ @Permission(action = "view"),
+ @Permission(action = "comment")
+})
+@Entity
+public class MemberImage implements Serializable
+{
+ private static final long serialVersionUID = -8088455267213832920L;
+
+ private Integer imageId;
+ private Member member;
+ private byte[] data;
+ private String contentType;
+ private String caption;
+
+ @Id @GeneratedValue
+ public Integer getImageId()
+ {
+ return imageId;
+ }
+
+ public void setImageId(Integer imageId)
+ {
+ this.imageId = imageId;
+ }
+
+ @ManyToOne
+ @JoinColumn(name = "MEMBER_ID")
+ public Member getMember()
+ {
+ return member;
+ }
+
+ public void setMember(Member member)
+ {
+ this.member = member;
+ }
+
+ public String getContentType()
+ {
+ return contentType;
+ }
+
+ public void setContentType(String contentType)
+ {
+ this.contentType = contentType;
+ }
+
+ public String getCaption()
+ {
+ return caption;
+ }
+
+ public void setCaption(String caption)
+ {
+ this.caption = caption;
+ }
+
+ @Lob
+ public byte[] getData()
+ {
+ return data;
+ }
+
+ public void setData(byte[] data)
+ {
+ this.data = data;
+ }
+
+}
Added: modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/MemberRole.java
===================================================================
--- modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/MemberRole.java (rev 0)
+++ modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/MemberRole.java 2010-03-25 02:33:21 UTC (rev 12264)
@@ -0,0 +1,76 @@
+package org.jboss.seam.example.seamspace;
+
+import java.io.Serializable;
+import java.util.Set;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.JoinTable;
+import javax.persistence.ManyToMany;
+
+import org.jboss.seam.annotations.security.management.RoleConditional;
+import org.jboss.seam.annotations.security.management.RoleGroups;
+import org.jboss.seam.annotations.security.management.RoleName;
+
+@Entity
+public class MemberRole implements Serializable
+{
+ private static final long serialVersionUID = 9177366120789064801L;
+
+ private Integer roleId;
+ private String name;
+ private boolean conditional;
+
+ private Set<MemberRole> groups;
+
+ @Id @GeneratedValue
+ public Integer getRoleId()
+ {
+ return roleId;
+ }
+
+ public void setRoleId(Integer roleId)
+ {
+ this.roleId = roleId;
+ }
+
+ @RoleName
+ public String getName()
+ {
+ return name;
+ }
+
+ public void setName(String name)
+ {
+ this.name = name;
+ }
+
+ @RoleGroups
+ @ManyToMany(targetEntity = MemberRole.class)
+ @JoinTable(name = "RoleGroup",
+ joinColumns = @JoinColumn(name = "RoleId"),
+ inverseJoinColumns = @JoinColumn(name = "MemberOf")
+ )
+ public Set<MemberRole> getGroups()
+ {
+ return groups;
+ }
+
+ public void setGroups(Set<MemberRole> groups)
+ {
+ this.groups = groups;
+ }
+
+ @RoleConditional
+ public boolean isConditional()
+ {
+ return conditional;
+ }
+
+ public void setConditional(boolean conditional)
+ {
+ this.conditional = conditional;
+ }
+}
Added: modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/PictureAction.java
===================================================================
--- modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/PictureAction.java (rev 0)
+++ modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/PictureAction.java 2010-03-25 02:33:21 UTC (rev 12264)
@@ -0,0 +1,41 @@
+package org.jboss.seam.example.seamspace;
+
+import static org.jboss.seam.ScopeType.CONVERSATION;
+
+import javax.persistence.EntityManager;
+
+import org.jboss.seam.annotations.Begin;
+import org.jboss.seam.annotations.In;
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Scope;
+import org.jboss.seam.core.Conversation;
+
+@Scope(CONVERSATION)
+@Name("pictureAction")
+public class PictureAction
+{
+ private MemberImage memberImage;
+
+ @In(required = false)
+ private Member authenticatedMember;
+
+ @In EntityManager entityManager;
+
+ @Begin
+ public void uploadPicture()
+ {
+ memberImage = new MemberImage();
+ }
+
+ public void savePicture()
+ {
+ memberImage.setMember(entityManager.find(Member.class, authenticatedMember.getMemberId()));
+ entityManager.persist(memberImage);
+ Conversation.instance().end();
+ }
+
+ public MemberImage getMemberImage()
+ {
+ return memberImage;
+ }
+}
Added: modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/PictureSearch.java
===================================================================
--- modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/PictureSearch.java (rev 0)
+++ modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/PictureSearch.java 2010-03-25 02:33:21 UTC (rev 12264)
@@ -0,0 +1,64 @@
+package org.jboss.seam.example.seamspace;
+
+import static org.jboss.seam.ScopeType.EVENT;
+
+import java.io.Serializable;
+import java.util.List;
+
+import javax.persistence.EntityManager;
+
+import org.jboss.seam.annotations.In;
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Out;
+import org.jboss.seam.annotations.Scope;
+import org.jboss.seam.annotations.security.Delete;
+import org.jboss.seam.annotations.web.RequestParameter;
+import org.jboss.seam.security.Identity;
+
+@Name("pictureSearch")
+@Scope(EVENT)
+public class PictureSearch implements Serializable
+{
+ private static final long serialVersionUID = -1868188969326866331L;
+
+ private String memberName;
+
+ @In
+ private EntityManager entityManager;
+
+ @Out(required = false)
+ private List<MemberImage> memberImages;
+
+ @RequestParameter
+ private Integer imageId;
+
+ public String getMemberName()
+ {
+ return memberName;
+ }
+
+ public void setMemberName(String memberName)
+ {
+ this.memberName = memberName;
+ }
+
+ public void delete(@Delete MemberImage image)
+ {
+ entityManager.remove(image);
+ }
+
+ public MemberImage lookupImage()
+ {
+ return entityManager.find(MemberImage.class, imageId);
+ }
+
+ @SuppressWarnings("unchecked")
+ public void loadMemberPictures()
+ {
+ memberImages = (List<MemberImage>) entityManager.createQuery(
+ "select i from MemberImage i where i.member.memberName = :name and not i = i.member.picture")
+ .setParameter("name", memberName)
+ .getResultList();
+ Identity.instance().filterByPermission(memberImages, "view");
+ }
+}
Added: modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/ProfileAction.java
===================================================================
--- modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/ProfileAction.java (rev 0)
+++ modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/ProfileAction.java 2010-03-25 02:33:21 UTC (rev 12264)
@@ -0,0 +1,132 @@
+package org.jboss.seam.example.seamspace;
+
+import static org.jboss.seam.ScopeType.CONVERSATION;
+import static org.jboss.seam.ScopeType.EVENT;
+
+import java.util.List;
+import java.util.Random;
+
+import javax.ejb.Remove;
+import javax.persistence.EntityManager;
+import javax.persistence.NoResultException;
+
+import org.jboss.seam.annotations.Destroy;
+import org.jboss.seam.annotations.Factory;
+import org.jboss.seam.annotations.In;
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Out;
+import org.jboss.seam.annotations.web.RequestParameter;
+import org.jboss.seam.annotations.Scope;
+
+@Name("profile")
+@Scope(EVENT)
+public class ProfileAction
+{
+ @RequestParameter
+ private String name;
+
+ @In(required = false) @Out(required = false, scope = CONVERSATION)
+ private Member selectedMember;
+
+ @In(required = false)
+ private Member authenticatedMember;
+
+ @Out(required = false)
+ List<Member> newMembers;
+
+ @Out(required = false)
+ List<MemberBlog> memberBlogs;
+
+ @In
+ private EntityManager entityManager;
+
+ @Factory("selectedMember")
+ public void display()
+ {
+ if (name == null && authenticatedMember != null)
+ {
+ selectedMember = (Member) entityManager.find(Member.class,
+ authenticatedMember.getMemberId());
+ }
+ else if (name != null)
+ {
+ try
+ {
+ selectedMember = (Member) entityManager.createQuery(
+ "from Member where memberName = :memberName")
+ .setParameter("memberName", name)
+ .getSingleResult();
+ }
+ catch (NoResultException ex) { }
+ }
+ }
+
+ /**
+ * Returns the 5 latest blog entries for a member
+ */
+ @SuppressWarnings("unchecked")
+ public List<MemberBlog> getLatestBlogs()
+ {
+ return entityManager.createQuery(
+ "from MemberBlog b where b.member = :member order by b.entryDate desc")
+ .setParameter("member", selectedMember)
+ .setMaxResults(5)
+ .getResultList();
+ }
+
+ /**
+ * Used to read all blog entries for a member
+ */
+ @SuppressWarnings("unchecked")
+ @Factory("memberBlogs")
+ public void getMemberBlogs()
+ {
+ if (name == null && authenticatedMember != null)
+ {
+ name = authenticatedMember.getMemberName();
+ }
+
+ memberBlogs = entityManager.createQuery(
+ "from MemberBlog b where b.member.memberName = :memberName order by b.entryDate desc")
+ .setParameter("memberName", name)
+ .getResultList();
+ }
+
+ @SuppressWarnings("unchecked")
+ @Factory("newMembers")
+ public void newMembers()
+ {
+ newMembers = entityManager.createQuery(
+ "from Member order by memberSince desc")
+ .setMaxResults(10)
+ .getResultList();
+
+ // Randomly select 3 of the latest 10 members
+ Random rnd = new Random(System.currentTimeMillis());
+ while (newMembers.size() > 3)
+ {
+ newMembers.remove(rnd.nextInt(newMembers.size()));
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public List<Member> getFriends()
+ {
+ return entityManager.createQuery(
+ "select f.friend from MemberFriend f where f.member = :member and authorized = true")
+ .setParameter("member", selectedMember)
+ .getResultList();
+ }
+
+ @SuppressWarnings("unchecked")
+ public List<FriendComment> getFriendComments()
+ {
+ return entityManager.createQuery(
+ "from FriendComment c where c.member = :member order by commentDate desc")
+ .setParameter("member", selectedMember)
+ .getResultList();
+ }
+
+ @Remove @Destroy
+ public void destroy() { }
+}
Added: modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/RegisterAction.java
===================================================================
--- modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/RegisterAction.java (rev 0)
+++ modules/security/trunk/examples/seamspace/src/main/java/org/jboss/seam/security/examples/seamspace/RegisterAction.java 2010-03-25 02:33:21 UTC (rev 12264)
@@ -0,0 +1,203 @@
+package org.jboss.seam.example.seamspace;
+
+import static org.jboss.seam.ScopeType.CONVERSATION;
+
+import java.util.Date;
+
+import javax.ejb.Remove;
+import javax.persistence.EntityManager;
+
+import org.jboss.seam.annotations.Begin;
+import org.jboss.seam.annotations.Destroy;
+import org.jboss.seam.annotations.End;
+import org.jboss.seam.annotations.In;
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Observer;
+import org.jboss.seam.annotations.Scope;
+import org.jboss.seam.faces.FacesMessages;
+import org.jboss.seam.security.Identity;
+import org.jboss.seam.security.RunAsOperation;
+import org.jboss.seam.security.management.IdentityManager;
+import org.jboss.seam.security.management.JpaIdentityStore;
+
+@Scope(CONVERSATION)
+@Name("register")
+public class RegisterAction
+{
+ private Member member;
+
+ @In
+ private EntityManager entityManager;
+
+ @In
+ private Identity identity;
+
+ @In
+ private IdentityManager identityManager;
+
+ private MemberAccount newAccount;
+
+ private String username;
+
+ /**
+ * Password confirmation
+ */
+ private String password;
+ private String confirm;
+
+ private String gender;
+
+ private byte[] picture;
+ private String pictureContentType;
+
+ private boolean verified;
+
+ @Begin
+ public void start()
+ {
+ member = new Member();
+ }
+
+ public void next()
+ {
+ member.setGender(Member.Gender.valueOf(gender.toLowerCase()));
+
+ verified = (confirm != null && confirm.equals(password));
+
+ if (!verified)
+ {
+ FacesMessages.instance().addToControl("confirmPassword", "Passwords do not match");
+ }
+ }
+
+ @Observer(JpaIdentityStore.EVENT_USER_CREATED)
+ public void accountCreated(MemberAccount account)
+ {
+ // The user *may* have been created from the user manager screen. In that
+ // case, create a dummy Member record just for the purpose of demonstrating the
+ // identity management API
+ if (member == null)
+ {
+ member = new Member();
+ member.setMemberName(account.getUsername());
+ member.setGender(Member.Gender.male);
+ member.setFirstName("John");
+ member.setLastName("Doe");
+ member.setEmail(account.getUsername() + "@nowhere.com");
+ member.setDob(new Date());
+ member.setMemberSince(new Date());
+ entityManager.persist(member);
+ }
+
+ account.setMember(member);
+ this.newAccount = account;
+ }
+
+ @End
+ public void uploadPicture()
+ {
+ member.setMemberSince(new Date());
+ entityManager.persist(member);
+
+ new RunAsOperation() {
+ public void execute() {
+ identityManager.createUser(username, password);
+ identityManager.grantRole(username, "user");
+ }
+ }.addRole("admin")
+ .run();
+
+ newAccount.setMember(member);
+ newAccount = entityManager.merge(newAccount);
+
+ if (picture != null && picture.length > 0)
+ {
+ MemberImage img = new MemberImage();
+ img.setData(picture);
+ img.setMember(member);
+ img.setContentType(pictureContentType);
+ entityManager.persist(img);
+ member.setPicture(img);
+
+ member = entityManager.merge(member);
+ }
+
+ // Login the user
+ identity.getCredentials().setUsername(username);
+ identity.getCredentials().setPassword(password);
+ identity.login();
+ }
+
+ public Member getMember()
+ {
+ return member;
+ }
+
+ public String getUsername()
+ {
+ return username;
+ }
+
+ public void setUsername(String username)
+ {
+ this.username = username;
+ }
+
+ public String getPassword()
+ {
+ return password;
+ }
+
+ public void setPassword(String password)
+ {
+ this.password = password;
+ }
+
+ public String getConfirm()
+ {
+ return confirm;
+ }
+
+ public void setConfirm(String confirm)
+ {
+ this.confirm = confirm;
+ }
+
+ public String getGender()
+ {
+ return gender;
+ }
+
+ public void setGender(String gender)
+ {
+ this.gender = gender;
+ }
+
+ public void setPicture(byte[] picture)
+ {
+ this.picture = picture;
+ }
+
+ public byte[] getPicture()
+ {
+ return picture;
+ }
+
+ public String getPictureContentType()
+ {
+ return pictureContentType;
+ }
+
+ public void setPictureContentType(String contentType)
+ {
+ this.pictureContentType = contentType;
+ }
+
+ public boolean isVerified()
+ {
+ return verified;
+ }
+
+ @Destroy @Remove
+ public void destroy() {}
+}
Added: modules/security/trunk/examples/seamspace/src/main/webapp/WEB-INF/faces-config.xml
===================================================================
--- modules/security/trunk/examples/seamspace/src/main/webapp/WEB-INF/faces-config.xml (rev 0)
+++ modules/security/trunk/examples/seamspace/src/main/webapp/WEB-INF/faces-config.xml 2010-03-25 02:33:21 UTC (rev 12264)
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<faces-config version="1.2"
+ xmlns="http://java.sun.com/xml/ns/javaee"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_1_2.xsd">
+
+ <application>
+ <view-handler>com.sun.facelets.FaceletViewHandler</view-handler>
+ </application>
+
+</faces-config>
Added: modules/security/trunk/examples/seamspace/src/main/webapp/WEB-INF/web.xml
===================================================================
--- modules/security/trunk/examples/seamspace/src/main/webapp/WEB-INF/web.xml (rev 0)
+++ modules/security/trunk/examples/seamspace/src/main/webapp/WEB-INF/web.xml 2010-03-25 02:33:21 UTC (rev 12264)
@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app version="2.5"
+ xmlns="http://java.sun.com/xml/ns/javaee"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
+
+ <display-name>SeamSpace Example</display-name>
+
+ <!-- RichFaces -->
+
+ <context-param>
+ <param-name>org.richfaces.SKIN</param-name>
+ <param-value>blueSky</param-value>
+ </context-param>
+
+ <!-- Seam -->
+
+ <listener>
+ <listener-class>org.jboss.seam.servlet.SeamListener</listener-class>
+ </listener>
+
+ <servlet>
+ <servlet-name>Seam Resource Servlet</servlet-name>
+ <servlet-class>org.jboss.seam.servlet.SeamResourceServlet</servlet-class>
+ </servlet>
+
+ <servlet-mapping>
+ <servlet-name>Seam Resource Servlet</servlet-name>
+ <url-pattern>/seam/resource/*</url-pattern>
+ </servlet-mapping>
+
+ <filter>
+ <filter-name>Seam Filter</filter-name>
+ <filter-class>org.jboss.seam.servlet.SeamFilter</filter-class>
+ </filter>
+
+ <filter-mapping>
+ <filter-name>Seam Filter</filter-name>
+ <url-pattern>/*</url-pattern>
+ </filter-mapping>
+
+ <context-param>
+ <param-name>facelets.DEVELOPMENT</param-name>
+ <param-value>true</param-value>
+ </context-param>
+
+ <context-param>
+ <param-name>javax.faces.DEFAULT_SUFFIX</param-name>
+ <param-value>.xhtml</param-value>
+ </context-param>
+
+ <!-- Faces Servlet -->
+
+ <servlet>
+ <servlet-name>Faces Servlet</servlet-name>
+ <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
+ <load-on-startup>1</load-on-startup>
+ </servlet>
+
+ <servlet-mapping>
+ <servlet-name>Faces Servlet</servlet-name>
+ <url-pattern>*.seam</url-pattern>
+ </servlet-mapping>
+
+ <!-- Content Servlet -->
+
+ <servlet>
+ <servlet-name>Content Servlet</servlet-name>
+ <servlet-class>org.jboss.seam.example.seamspace.ContentServlet</servlet-class>
+ </servlet>
+
+ <servlet-mapping>
+ <servlet-name>Content Servlet</servlet-name>
+ <url-pattern>/content/*</url-pattern>
+ </servlet-mapping>
+
+ <session-config>
+ <session-timeout>10</session-timeout>
+ </session-config>
+</web-app>
Added: modules/security/trunk/examples/seamspace/src/main/webapp/blog.xhtml
===================================================================
--- modules/security/trunk/examples/seamspace/src/main/webapp/blog.xhtml (rev 0)
+++ modules/security/trunk/examples/seamspace/src/main/webapp/blog.xhtml 2010-03-25 02:33:21 UTC (rev 12264)
@@ -0,0 +1,60 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:s="http://jboss.com/products/seam/taglib">
+
+ <ui:composition template="template.xhtml">
+ <ui:define name="content">
+
+ <div class="errors"><h:messages globalOnly="true"/></div>
+
+ <s:div rendered="#{selectedMember == null}">
+ Sorry, but this member does not exist.
+ </s:div>
+
+ <s:div rendered="#{selectedMember != null}">
+
+ <s:div id="blogMemberCard">
+ <s:link view="/profile.seam" propagation="none">
+ #{selectedMember.memberName}<br/>
+ <h:graphicImage value="/content/images?id=#{selectedMember.picture.imageId}&width=90"/>
+ </s:link>
+
+ <br style="clear:both"/>
+ </s:div>
+
+ <s:div id="blog">
+ <ui:repeat value="#{memberBlogs}" var="memberBlog">
+ <div class="blogEntry">
+ <div class="blogDate">#{memberBlog.formattedEntryDate}</div>
+ <div class="blogTitle">#{memberBlog.title}</div>
+ <div class="blogText"><s:formattedText value="#{memberBlog.text}"/></div>
+ <div class="blogFooter">
+
+ [<s:link view="/blogentry.seam" propagation="none">
+ <f:param name="name" value="#{selectedMember.memberName}"/>
+ <f:param name="blogId" value="#{memberBlog.blogId}"/>
+ #{memberBlog.commentCount} Comment#{memberBlog.commentCount != 1 ? "s" : ""}
+ </s:link>]
+
+ <s:span rendered="#{s:hasPermission('blog','createComment')}">
+ [<s:link view="/comment.seam" value="Add Comment" propagation="none">
+ <f:param name="name" value="#{selectedMember.memberName}"/>
+ <f:param name="blogId" value="#{memberBlog.blogId}"/>
+ </s:link>]
+ </s:span>
+ </div>
+ </div>
+ </ui:repeat>
+ </s:div>
+
+ </s:div>
+
+ <br class="clear"/>
+
+ </ui:define>
+
+ </ui:composition>
+</html>
Added: modules/security/trunk/examples/seamspace/src/main/webapp/blogentry.xhtml
===================================================================
--- modules/security/trunk/examples/seamspace/src/main/webapp/blogentry.xhtml (rev 0)
+++ modules/security/trunk/examples/seamspace/src/main/webapp/blogentry.xhtml 2010-03-25 02:33:21 UTC (rev 12264)
@@ -0,0 +1,74 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:s="http://jboss.com/products/seam/taglib">
+
+ <ui:composition template="template.xhtml">
+ <ui:define name="content">
+
+ <div class="errors"><h:messages globalOnly="true"/></div>
+
+ <s:div rendered="#{selectedBlog == null}">
+ Sorry, but this blog entry does not exist.
+ </s:div>
+
+ <s:div rendered="#{selectedBlog != null}">
+
+ <s:div id="blogMemberCard">
+ <s:link view="/profile.seam" propagation="none">
+ #{selectedMember.memberName}<br/>
+ <h:graphicImage value="/content/images?id=#{selectedMember.picture.imageId}&width=90"/>
+ </s:link>
+
+ <br style="clear:both"/>
+ </s:div>
+
+ <s:div id="blog">
+ <div class="blogEntry">
+ <div class="blogDate">#{selectedBlog.formattedEntryDate}</div>
+ <div class="blogTitle">#{selectedBlog.title}</div>
+ <div class="blogText"><s:formattedText value="#{selectedBlog.text}"/></div>
+ <div class="blogFooter">
+ <s:span rendered="#{s:hasPermission(selectedBlog, 'create')}">
+ [<s:link action="#{commentAction.createComment}" value="Add Comment"/>]
+ </s:span>
+ [<s:link view="/blog.seam" value="View all blog entries" propagation="none">
+ <f:param name="name" value="#{selectedMember.memberName}"/>
+ </s:link>]
+ </div>
+ </div>
+
+ <ui:repeat value="#{selectedBlog.sortedComments}" var="comment">
+ <table class="blogComment">
+ <tr>
+ <td class="blogCommentor">
+ <s:link view="/profile.seam" propagation="none">
+ <f:param name="name" value="#{comment.commentor.memberName}"/>
+ #{comment.commentor.memberName}<br/>
+ <h:graphicImage value="/content/images?id=#{comment.commentor.picture.imageId}&width=90"/>
+ </s:link>
+ </td>
+
+ <td class="blogCommentText">
+ <p><s:formattedText value="#{comment.comment}"/></p>
+ <p>Posted by
+ <s:link view="/profile.seam" value="#{comment.commentor.memberName}" propagation="none">
+ <f:param name="name" value="#{comment.commentor.memberName}"/>
+ </s:link> on #{comment.formattedCommentDate}
+ </p>
+ </td>
+ </tr>
+ </table>
+ </ui:repeat>
+ </s:div>
+
+ </s:div>
+
+ <br class="clear"/>
+
+ </ui:define>
+
+ </ui:composition>
+</html>
Added: modules/security/trunk/examples/seamspace/src/main/webapp/comment.xhtml
===================================================================
--- modules/security/trunk/examples/seamspace/src/main/webapp/comment.xhtml (rev 0)
+++ modules/security/trunk/examples/seamspace/src/main/webapp/comment.xhtml 2010-03-25 02:33:21 UTC (rev 12264)
@@ -0,0 +1,89 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:s="http://jboss.com/products/seam/taglib">
+
+ <ui:composition template="template.xhtml">
+ <ui:define name="content">
+
+ <div class="errors"><h:messages globalOnly="true"/></div>
+
+ <s:div rendered="#{commentAction.comment == null}">
+ Could not create comment.
+ </s:div>
+
+ <s:div rendered="#{selectedMember != null}">
+
+ <s:div id="blogMemberCard">
+ <s:link view="/profile.seam" propagation="none">
+ #{selectedMember.memberName}<br/>
+ <h:graphicImage value="/content/images?id=#{selectedMember.picture.imageId}&width=90"/>
+ </s:link>
+
+ <br style="clear:both"/>
+ </s:div>
+
+ <s:div id="blog">
+ <div class="blogEntry">
+ <div class="blogDate">#{selectedBlog.formattedEntryDate}</div>
+ <div class="blogTitle">#{selectedBlog.title}</div>
+ <div class="blogText"><s:formattedText value="#{selectedBlog.text}"/></div>
+ </div>
+
+ <s:div rendered="#{commentAction.comment.comment != null}">
+ Preview:
+ <table class="blogComment">
+ <tr>
+ <td class="blogCommentText">
+ <p><s:formattedText value="#{commentAction.comment.comment}"/></p>
+ </td>
+ </tr>
+ </table>
+ </s:div>
+
+ <div class="commentEntry">
+ <h:form>
+
+ <h:outputLabel for="comment">Please type your comment</h:outputLabel><br/>
+ <h:inputTextarea id="comment" value="#{commentAction.comment.comment}"/><br/>
+
+ <div class="buttons">
+ <h:commandButton action="#{commentAction.saveComment}" value="Add comment" styleClass="action"/>
+ <h:commandButton value="Preview" styleClass="action"/>
+ </div>
+
+ <br class="clear"/>
+ </h:form>
+ </div>
+
+ <div>
+ <b>Seam Text Quick Reference</b><br/>
+ <pre><code>
+*bold* /italic/ |monospace| -strikethrough- ^super^ _underline_
+
++Big Heading
+Headings must be followed by text
+
+++Smaller heading
+Paragraphs are ended with a blank line.
+
+#ordered list item
+
+=unordered list item
+
+"quoted text"
+ </code></pre>
+ </div>
+
+ </s:div>
+
+ </s:div>
+
+ <br class="clear"/>
+
+ </ui:define>
+
+ </ui:composition>
+</html>
Added: modules/security/trunk/examples/seamspace/src/main/webapp/createBlog.xhtml
===================================================================
--- modules/security/trunk/examples/seamspace/src/main/webapp/createBlog.xhtml (rev 0)
+++ modules/security/trunk/examples/seamspace/src/main/webapp/createBlog.xhtml 2010-03-25 02:33:21 UTC (rev 12264)
@@ -0,0 +1,84 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:s="http://jboss.com/products/seam/taglib">
+
+ <ui:composition template="template.xhtml">
+ <ui:define name="content">
+
+ <div class="errors"><h:messages globalOnly="true"/></div>
+
+ <s:div rendered="#{selectedBlog == null}">
+ Sorry, but this blog entry does not exist.
+ </s:div>
+
+ <s:div rendered="#{selectedBlog != null}">
+
+ <s:div id="blogMemberCard">
+ <s:link view="/profile.seam" propagation="none">
+ #{selectedMember.memberName}<br/>
+ <h:graphicImage value="/content/images?id=#{selectedMember.picture.imageId}&width=90"/>
+ </s:link>
+
+ <br style="clear:both"/>
+ </s:div>
+
+ <s:div id="blog">
+ <s:div rendered="#{selectedBlog.text != null}" styleClass="blogEntry">
+ Preview:
+ <p><s:formattedText value="#{selectedBlog.text}"/></p>
+ </s:div>
+
+ <div class="blogEntry">
+ <h:form id="newBlog">
+
+ <div class="formRow">
+ <h:outputLabel for="title">Please type a title for your blog entry</h:outputLabel><br/>
+ <h:inputText id="title" value="#{selectedBlog.title}" styleClass="title"/>
+ </div>
+
+ <div class="formRow">
+ <h:outputLabel for="text">Type your blog entry here</h:outputLabel><br/>
+ <h:inputTextarea id="text" value="#{selectedBlog.text}"/>
+ </div>
+
+ <div class="buttons">
+ <h:commandButton id="submit" action="#{blog.saveEntry}" value="Add entry" styleClass="action"/>
+ <h:commandButton id="preview" value="Preview" styleClass="action"/>
+ </div>
+
+ <br class="clear"/>
+ </h:form>
+ </div>
+
+ <div>
+ <b>Seam Text Quick Reference</b><br/>
+ <pre><code>
+*bold* /italic/ |monospace| -strikethrough- ^super^ _underline_
+
++Big Heading
+Headings must be followed by text
+
+++Smaller heading
+Paragraphs are ended with a blank line.
+
+#ordered list item
+
+=unordered list item
+
+"quoted text"
+ </code></pre>
+ </div>
+
+ </s:div>
+
+ </s:div>
+
+ <br class="clear"/>
+
+ </ui:define>
+
+ </ui:composition>
+</html>
Added: modules/security/trunk/examples/seamspace/src/main/webapp/friendcomment.xhtml
===================================================================
--- modules/security/trunk/examples/seamspace/src/main/webapp/friendcomment.xhtml (rev 0)
+++ modules/security/trunk/examples/seamspace/src/main/webapp/friendcomment.xhtml 2010-03-25 02:33:21 UTC (rev 12264)
@@ -0,0 +1,84 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:s="http://jboss.com/products/seam/taglib">
+
+ <ui:composition template="template.xhtml">
+ <ui:define name="content">
+
+ <div class="errors"><h:messages globalOnly="true"/></div>
+
+ <s:div rendered="#{friendComment == null}">
+ Could not create comment.
+ </s:div>
+
+ <s:div rendered="#{friendComment != null}">
+
+ <s:div id="blogMemberCard">
+ <h:outputLink value="profile.seam?name=#{friendComment.member.memberName}">
+ #{friendComment.member.memberName}<br/>
+ <h:graphicImage value="/content/images?id=#{friendComment.member.picture.imageId}&width=90"/>
+ </h:outputLink>
+
+ <br style="clear:both"/>
+ </s:div>
+
+ <s:div id="blog">
+
+ <s:div rendered="#{friendComment.comment != null}">
+ Preview:
+ <table class="blogComment">
+ <tr>
+ <td class="blogCommentText">
+ <p><s:formattedText value="#{friendComment.comment}"/></p>
+ </td>
+ </tr>
+ </table>
+ </s:div>
+
+ <div class="commentEntry">
+ <h:form>
+
+ <h:outputLabel for="comment">Please type your comment for #{friendComment.member.memberName}</h:outputLabel><br/>
+ <h:inputTextarea id="comment" value="#{friendComment.comment}"/><br/>
+
+ <div class="buttons">
+ <h:commandButton action="#{friendAction.saveComment}" value="Add comment" styleClass="action"/>
+ <h:commandButton value="Preview" styleClass="action"/>
+ </div>
+
+ <br class="clear"/>
+ </h:form>
+ </div>
+
+ <div>
+ <b>Seam Text Quick Reference</b><br/>
+ <pre><code>
+*bold* /italic/ |monospace| -strikethrough- ^super^ _underline_
+
++Big Heading
+Headings must be followed by text
+
+++Smaller heading
+Paragraphs are ended with a blank line.
+
+#ordered list item
+
+=unordered list item
+
+"quoted text"
+ </code></pre>
+ </div>
+
+ </s:div>
+
+ </s:div>
+
+ <br class="clear"/>
+
+ </ui:define>
+
+ </ui:composition>
+</html>
Added: modules/security/trunk/examples/seamspace/src/main/webapp/friendrequest.xhtml
===================================================================
--- modules/security/trunk/examples/seamspace/src/main/webapp/friendrequest.xhtml (rev 0)
+++ modules/security/trunk/examples/seamspace/src/main/webapp/friendrequest.xhtml 2010-03-25 02:33:21 UTC (rev 12264)
@@ -0,0 +1,56 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:s="http://jboss.com/products/seam/taglib">
+
+ <ui:composition template="template.xhtml">
+ <ui:define name="content">
+
+ <div class="errors"><h:messages globalOnly="true"/></div>
+
+ <s:div rendered="#{friendRequest == null}">
+ Could not create friend request.
+ </s:div>
+
+ <s:div rendered="#{friendRequest != null}">
+
+ <s:div id="blogMemberCard">
+ <s:link view="/profile.xhtml" value="#{friendRequest.member.memberName}" propagation="none">
+ <f:param name="name" value="#{friendRequest.member.memberName}"/>
+ <h:graphicImage value="/content/images?id=#{friendRequest.member.picture.imageId}&width=90"/>
+ </s:link>
+
+ <br style="clear:both"/>
+ </s:div>
+
+ <div class="friendRequest">
+ <h1>Send a friend request</h1>
+
+ <p>
+ Use this form to request that <b>#{friendRequest.member.memberName}</b> adds you to
+ #{friendRequest.member.gender.possessive} friends list.
+ </p>
+
+ <h:form>
+
+ <h:outputLabel for="introduction">Please type an introduction message</h:outputLabel><br/>
+ <h:inputTextarea id="introduction" value="#{friendRequest.introduction}"/><br/>
+
+ <div class="buttons">
+ <h:commandButton action="#{friendAction.saveRequest}" value="Send request" styleClass="action"/>
+ </div>
+
+ <br class="clear"/>
+ </h:form>
+ </div>
+
+ </s:div>
+
+ <br class="clear"/>
+
+ </ui:define>
+
+ </ui:composition>
+</html>
Added: modules/security/trunk/examples/seamspace/src/main/webapp/hashgen.xhtml
===================================================================
--- modules/security/trunk/examples/seamspace/src/main/webapp/hashgen.xhtml (rev 0)
+++ modules/security/trunk/examples/seamspace/src/main/webapp/hashgen.xhtml 2010-03-25 02:33:21 UTC (rev 12264)
@@ -0,0 +1,49 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:s="http://jboss.com/products/seam/taglib">
+
+ <ui:composition template="template.xhtml">
+ <ui:define name="content">
+ <h1>Password Hash Generator</h1>
+
+ <p>
+ This page uses the methods in JpaIdentityStore to generate password hash values that you can
+ use in your own application's import.sql to create default accounts for your application.
+ </p>
+
+ <p>
+ Please note that you must have a property annotated @PasswordSalt for these hash values to work!
+ </p>
+
+ <h:form>
+
+ <div class="formRow">
+ <h:outputLabel for="password">Enter a password</h:outputLabel>
+ <h:inputText id="password" value="#{hashgenerator.password}" required="true" styleClass="wide"/>
+ <div class="validationError"><h:message for="password"/></div>
+ </div>
+
+ <div class="formRow">
+ <h:outputLabel for="salt">Password salt</h:outputLabel>
+ <h:inputText id="salt" value="#{hashgenerator.passwordSalt}" required="false" styleClass="wide"/>
+ <span>(Leave blank to generate a random salt)</span>
+ <div class="validationError"><h:message for="salt"/></div>
+ </div>
+
+ <h:commandButton action="#{hashgenerator.generate}" value="Generate hash"/>
+
+ </h:form>
+
+ <h2>Results</h2>
+
+ <div>Generated hash (hex encoded): <pre>#{hashgenerator.passwordHash}</pre></div>
+
+ <div>Example SQL:<br/><textarea style="width:640px;height:50px">#{hashgenerator.sql}</textarea></div>
+
+ </ui:define>
+
+ </ui:composition>
+</html>
Added: modules/security/trunk/examples/seamspace/src/main/webapp/home.xhtml
===================================================================
--- modules/security/trunk/examples/seamspace/src/main/webapp/home.xhtml (rev 0)
+++ modules/security/trunk/examples/seamspace/src/main/webapp/home.xhtml 2010-03-25 02:33:21 UTC (rev 12264)
@@ -0,0 +1,93 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:s="http://jboss.com/products/seam/taglib">
+
+ <ui:composition template="template.xhtml">
+ <ui:define name="content">
+ <div id="contentMain">
+ <h1>Welcome to seamspace!</h1>
+
+ <p>
+ This example project is an imitation of a popular social networking site, and has
+ been put together to demonstrate the various features of the Seam Security API.
+ </p>
+
+ <p><b>New!</b> You can now use the <s:link view="/hashgen.xhtml" value="Password Hash Generator"/>
+ page to generate password hashes for your own application.
+ </p>
+
+ </div>
+
+ <div id="contentDivider">
+ </div>
+
+ <div id="contentSide">
+ <div class="advertising"></div>
+
+ <h:form id="loginForm" rendered="#{not identity.loggedIn}">
+ <div class="memberLogin">
+ <div class="loginHeader">Member Login</div>
+
+ <h:messages id="messages" globalOnly="true"/>
+
+ <div class="loginRow">
+ <h:outputLabel for="name" value="Member name" styleClass="loginLabel"/>
+ <h:inputText id="name" value="#{credentials.username}"/>
+ </div>
+
+ <div class="validationMsg">
+ <h:message for="name"/>
+ </div>
+
+ <div class="loginRow">
+ <h:outputLabel for="password" value="Password" styleClass="loginLabel"/>
+ <h:inputSecret id="password" value="#{credentials.password}" redisplay="true"/>
+ </div>
+
+ <div class="validationMsg">
+ <h:message for="password"/>
+ </div>
+
+ <div class="loginRow">
+ <h:outputLabel for="rememberMe" value="Remember me" styleClass="loginLabel"/>
+ <h:selectBooleanCheckbox id="rememberMe" value="#{identity.rememberMe}"/>
+ </div>
+
+ <div class="buttons">
+ <h:commandButton id="login" value="LOGIN" action="#{identity.login}" styleClass="loginButton"/>
+ <h:commandButton id="register" value="SIGN UP!" action="#{register.start}" styleClass="registerButton"/>
+ </div>
+
+ <br class="clear"/>
+
+ </div>
+
+ <span>Tip: You can log in using <b>demo/demo</b> as the username/password</span>
+ </h:form>
+
+ <div class="newMembers">
+ <div class="newMembersHeader">Cool new members</div>
+
+ <ui:repeat value="#{newMembers}" var="newMember">
+ <div class="newMember">
+
+ <s:link view="/profile.seam" propagation="none">
+ <f:param name="name" value="#{newMember.memberName}"/>
+ #{newMember.memberName}<br/>
+ <h:graphicImage value="/content/images?id=#{newMember.picture.imageId}&width=90"/>
+ </s:link>
+
+ </div>
+ </ui:repeat>
+
+ <br class="clear"/>
+ </div>
+ </div>
+
+ </ui:define>
+
+ </ui:composition>
+</html>
Added: modules/security/trunk/examples/seamspace/src/main/webapp/imagepermissiondetail.page.xml
===================================================================
--- modules/security/trunk/examples/seamspace/src/main/webapp/imagepermissiondetail.page.xml (rev 0)
+++ modules/security/trunk/examples/seamspace/src/main/webapp/imagepermissiondetail.page.xml 2010-03-25 02:33:21 UTC (rev 12264)
@@ -0,0 +1,9 @@
+<page xmlns="http://jboss.com/products/seam/pages"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://jboss.com/products/seam/pages http://jboss.com/products/seam/pages-2.2.xsd">
+ <navigation from-action="#{imagePermission.applyPermissions}">
+ <rule if-outcome="success">
+ <redirect view-id="/imagepermissions.xhtml"/>
+ </rule>
+ </navigation>
+</page>
Added: modules/security/trunk/examples/seamspace/src/main/webapp/imagepermissiondetail.xhtml
===================================================================
--- modules/security/trunk/examples/seamspace/src/main/webapp/imagepermissiondetail.xhtml (rev 0)
+++ modules/security/trunk/examples/seamspace/src/main/webapp/imagepermissiondetail.xhtml 2010-03-25 02:33:21 UTC (rev 12264)
@@ -0,0 +1,89 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:rich="http://richfaces.org/rich"
+ xmlns:s="http://jboss.com/products/seam/taglib">
+
+ <ui:composition template="template.xhtml">
+
+ <ui:define name="head">
+ <link href="style/security.css" rel="stylesheet" type="text/css"/>
+ </ui:define>
+
+ <ui:define name="content">
+
+ <div id="contentMain">
+
+ <h2>Permission Details</h2>
+
+ <hr/>
+
+ <h:messages globalOnly="true"/>
+
+ <h:form>
+ <s:fragment rendered="#{imagePermission.recipient eq null}">
+ <h3>Recipients</h3>
+
+ <p>
+ Select the roles and/or friends that you wish to grant permissions to, for the following image
+ (Ctrl-click to select multiple):
+ </p>
+
+ <br class="clear"/>
+
+ <div class="thumbnail">
+ <h:graphicImage value="/content/images?id=#{permissionSearch.target.imageId}&width=90"/>
+ </div>
+
+ <br class="clear"/>
+
+ <div class="formRow">
+ <h:outputLabel for="roles" value="Roles" styleClass="formLabel"/>
+ <div class="selectMany">
+ <h:selectManyListbox id="roles" value="#{imagePermission.selectedRoles}" styleClass="roles" size="4">
+ <s:selectItems value="#{identityManager.listRoles()}" var="role" label="#{role}"/>
+ </h:selectManyListbox>
+ </div>
+ <div class="validationError"><h:message for="actions"/></div>
+ </div>
+
+ <div class="formRow">
+ <h:outputLabel for="friends" value="Friends" styleClass="formLabel"/>
+ <div class="selectMany">
+ <h:selectManyListbox id="friends" value="#{imagePermission.selectedFriends}" styleClass="roles" size="6">
+ <s:selectItems value="#{imagePermission.availableFriends}" var="friend" label="#{friend.memberName}"/>
+ <s:convertEntity />
+ </h:selectManyListbox>
+ </div>
+ <div class="validationError"><h:message for="friends"/></div>
+ </div>
+
+ </s:fragment>
+
+ <div class="formRow">
+ <h:outputLabel for="actions" value="Actions allowed" styleClass="formLabel"/>
+ <div class="selectMany">
+ <h:selectManyCheckbox id="actions" value="#{imagePermission.selectedActions}" layout="pageDirection" styleClass="roles">
+ <s:selectItems value="#{permissionManager.listAvailableActions(imagePermission.target)}" var="action" label="#{action}"/>
+ </h:selectManyCheckbox>
+ </div>
+ <div class="validationError"><h:message for="actions"/></div>
+ </div>
+
+ <div class="formButtons">
+ <h:commandButton value="Save" action="#{imagePermission.applyPermissions}" styleClass="formButton"/>
+ <s:button view="/imagepermissions.xhtml" value="Cancel" propagation="end" styleClass="formButton"/>
+ </div>
+
+ <br class="clear"/>
+
+ </h:form>
+
+ </div>
+
+ </ui:define>
+
+ </ui:composition>
+</html>
Added: modules/security/trunk/examples/seamspace/src/main/webapp/imagepermissions.page.xml
===================================================================
--- modules/security/trunk/examples/seamspace/src/main/webapp/imagepermissions.page.xml (rev 0)
+++ modules/security/trunk/examples/seamspace/src/main/webapp/imagepermissions.page.xml 2010-03-25 02:33:21 UTC (rev 12264)
@@ -0,0 +1,11 @@
+<page xmlns="http://jboss.com/products/seam/pages"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://jboss.com/products/seam/pages http://jboss.com/products/seam/pages-2.2.xsd"
+ action="#{permissionSearch.refresh}">
+ <navigation from-action="#{imagePermission.createPermission}">
+ <redirect view-id="/imagepermissiondetail.xhtml"/>
+ </navigation>
+ <navigation from-action="#{imagePermission.editPermission}">
+ <redirect view-id="/imagepermissiondetail.xhtml"/>
+ </navigation>
+</page>
Added: modules/security/trunk/examples/seamspace/src/main/webapp/imagepermissions.xhtml
===================================================================
--- modules/security/trunk/examples/seamspace/src/main/webapp/imagepermissions.xhtml (rev 0)
+++ modules/security/trunk/examples/seamspace/src/main/webapp/imagepermissions.xhtml 2010-03-25 02:33:21 UTC (rev 12264)
@@ -0,0 +1,82 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:s="http://jboss.com/products/seam/taglib">
+
+ <ui:composition template="template.xhtml">
+
+ <ui:define name="head">
+ <link href="style/security.css" rel="stylesheet" type="text/css"/>
+ </ui:define>
+
+ <ui:define name="content">
+
+ <script type="text/javascript">
+ function confirmRevoke()
+ {
+ return confirm("Are you sure you wish to revoke this permission? This action cannot be undone.");
+ }
+ </script>
+
+ <div id="contentMain">
+
+ <h2>Image Permissions</h2>
+
+ <div style="float: left">
+ <h3>Managing permissions for image:</h3>
+ </div>
+
+ <br class="clear"/>
+
+ <div class="thumbnail">
+ <h:graphicImage value="/content/images?id=#{permissionSearch.target.imageId}&width=90"/>
+ </div>
+
+ <br class="clear"/>
+
+ <s:button action="#{imagePermission.createPermission}"
+ styleClass="newpermission"
+ rendered="#{s:hasPermission(permissionSearch.target, 'seam.grant-permission')}"/>
+
+ <h:dataTable
+ id="threads"
+ value="#{recipients}"
+ var="recipient"
+ styleClass="security"
+ cellspacing="0"
+ headerClass="header"
+ rowClasses="odd,even"
+ columnClasses=",,action">
+ <h:column width="auto">
+ <f:facet name="header">
+ Recipient
+ </f:facet>
+ #{recipient.name}
+ </h:column>
+ <h:column width="auto">
+ <f:facet name="header">
+ Actions Allowed
+ </f:facet>
+ #{permissionSearch.getActions(recipient)}
+ </h:column>
+ <h:column width="auto">
+ <f:facet name="header">
+ Action
+ </f:facet>
+ <s:link value="Edit" action="#{imagePermission.editPermission}"
+ rendered="#{s:hasPermission(permissionSearch.target, 'seam.revoke-permission')}"/>
+ <span> | </span>
+ <s:link value="Revoke All" action="#{permissionSearch.revokeSelected}"
+ rendered="#{s:hasPermission(permissionSearch.target, 'seam.revoke-permission')}"
+ onclick="return confirmRevoke()"/>
+ </h:column>
+ </h:dataTable>
+
+ </div>
+
+ </ui:define>
+
+ </ui:composition>
+</html>
Added: modules/security/trunk/examples/seamspace/src/main/webapp/images/bg_button.png
===================================================================
(Binary files differ)
Property changes on: modules/security/trunk/examples/seamspace/src/main/webapp/images/bg_button.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: modules/security/trunk/examples/seamspace/src/main/webapp/images/checkmark.png
===================================================================
(Binary files differ)
Property changes on: modules/security/trunk/examples/seamspace/src/main/webapp/images/checkmark.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: modules/security/trunk/examples/seamspace/src/main/webapp/images/cross.png
===================================================================
(Binary files differ)
Property changes on: modules/security/trunk/examples/seamspace/src/main/webapp/images/cross.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: modules/security/trunk/examples/seamspace/src/main/webapp/images/ellipsis.png
===================================================================
(Binary files differ)
Property changes on: modules/security/trunk/examples/seamspace/src/main/webapp/images/ellipsis.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: modules/security/trunk/examples/seamspace/src/main/webapp/images/no_image.png
===================================================================
(Binary files differ)
Property changes on: modules/security/trunk/examples/seamspace/src/main/webapp/images/no_image.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: modules/security/trunk/examples/seamspace/src/main/webapp/index.html
===================================================================
--- modules/security/trunk/examples/seamspace/src/main/webapp/index.html (rev 0)
+++ modules/security/trunk/examples/seamspace/src/main/webapp/index.html 2010-03-25 02:33:21 UTC (rev 12264)
@@ -0,0 +1,5 @@
+<html>
+<head>
+ <meta http-equiv="Refresh" content="0; URL=home.seam">
+</head>
+</html>
\ No newline at end of file
Added: modules/security/trunk/examples/seamspace/src/main/webapp/lightbox/builder.js
===================================================================
--- modules/security/trunk/examples/seamspace/src/main/webapp/lightbox/builder.js (rev 0)
+++ modules/security/trunk/examples/seamspace/src/main/webapp/lightbox/builder.js 2010-03-25 02:33:21 UTC (rev 12264)
@@ -0,0 +1,136 @@
+// script.aculo.us builder.js v1.8.1, Thu Jan 03 22:07:12 -0500 2008
+
+// Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
+//
+// script.aculo.us is freely distributable under the terms of an MIT-style license.
+// For details, see the script.aculo.us web site: http://script.aculo.us/
+
+var Builder = {
+ NODEMAP: {
+ AREA: 'map',
+ CAPTION: 'table',
+ COL: 'table',
+ COLGROUP: 'table',
+ LEGEND: 'fieldset',
+ OPTGROUP: 'select',
+ OPTION: 'select',
+ PARAM: 'object',
+ TBODY: 'table',
+ TD: 'table',
+ TFOOT: 'table',
+ TH: 'table',
+ THEAD: 'table',
+ TR: 'table'
+ },
+ // note: For Firefox < 1.5, OPTION and OPTGROUP tags are currently broken,
+ // due to a Firefox bug
+ node: function(elementName) {
+ elementName = elementName.toUpperCase();
+
+ // try innerHTML approach
+ var parentTag = this.NODEMAP[elementName] || 'div';
+ var parentElement = document.createElement(parentTag);
+ try { // prevent IE "feature": http://dev.rubyonrails.org/ticket/2707
+ parentElement.innerHTML = "<" + elementName + "></" + elementName + ">";
+ } catch(e) {}
+ var element = parentElement.firstChild || null;
+
+ // see if browser added wrapping tags
+ if(element && (element.tagName.toUpperCase() != elementName))
+ element = element.getElementsByTagName(elementName)[0];
+
+ // fallback to createElement approach
+ if(!element) element = document.createElement(elementName);
+
+ // abort if nothing could be created
+ if(!element) return;
+
+ // attributes (or text)
+ if(arguments[1])
+ if(this._isStringOrNumber(arguments[1]) ||
+ (arguments[1] instanceof Array) ||
+ arguments[1].tagName) {
+ this._children(element, arguments[1]);
+ } else {
+ var attrs = this._attributes(arguments[1]);
+ if(attrs.length) {
+ try { // prevent IE "feature": http://dev.rubyonrails.org/ticket/2707
+ parentElement.innerHTML = "<" +elementName + " " +
+ attrs + "></" + elementName + ">";
+ } catch(e) {}
+ element = parentElement.firstChild || null;
+ // workaround firefox 1.0.X bug
+ if(!element) {
+ element = document.createElement(elementName);
+ for(attr in arguments[1])
+ element[attr == 'class' ? 'className' : attr] = arguments[1][attr];
+ }
+ if(element.tagName.toUpperCase() != elementName)
+ element = parentElement.getElementsByTagName(elementName)[0];
+ }
+ }
+
+ // text, or array of children
+ if(arguments[2])
+ this._children(element, arguments[2]);
+
+ return element;
+ },
+ _text: function(text) {
+ return document.createTextNode(text);
+ },
+
+ ATTR_MAP: {
+ 'className': 'class',
+ 'htmlFor': 'for'
+ },
+
+ _attributes: function(attributes) {
+ var attrs = [];
+ for(attribute in attributes)
+ attrs.push((attribute in this.ATTR_MAP ? this.ATTR_MAP[attribute] : attribute) +
+ '="' + attributes[attribute].toString().escapeHTML().gsub(/"/,'"') + '"');
+ return attrs.join(" ");
+ },
+ _children: function(element, children) {
+ if(children.tagName) {
+ element.appendChild(children);
+ return;
+ }
+ if(typeof children=='object') { // array can hold nodes and text
+ children.flatten().each( function(e) {
+ if(typeof e=='object')
+ element.appendChild(e)
+ else
+ if(Builder._isStringOrNumber(e))
+ element.appendChild(Builder._text(e));
+ });
+ } else
+ if(Builder._isStringOrNumber(children))
+ element.appendChild(Builder._text(children));
+ },
+ _isStringOrNumber: function(param) {
+ return(typeof param=='string' || typeof param=='number');
+ },
+ build: function(html) {
+ var element = this.node('div');
+ $(element).update(html.strip());
+ return element.down();
+ },
+ dump: function(scope) {
+ if(typeof scope != 'object' && typeof scope != 'function') scope = window; //global scope
+
+ var tags = ("A ABBR ACRONYM ADDRESS APPLET AREA B BASE BASEFONT BDO BIG BLOCKQUOTE BODY " +
+ "BR BUTTON CAPTION CENTER CITE CODE COL COLGROUP DD DEL DFN DIR DIV DL DT EM FIELDSET " +
+ "FONT FORM FRAME FRAMESET H1 H2 H3 H4 H5 H6 HEAD HR HTML I IFRAME IMG INPUT INS ISINDEX "+
+ "KBD LABEL LEGEND LI LINK MAP MENU META NOFRAMES NOSCRIPT OBJECT OL OPTGROUP OPTION P "+
+ "PARAM PRE Q S SAMP SCRIPT SELECT SMALL SPAN STRIKE STRONG STYLE SUB SUP TABLE TBODY TD "+
+ "TEXTAREA TFOOT TH THEAD TITLE TR TT U UL VAR").split(/\s+/);
+
+ tags.each( function(tag){
+ scope[tag] = function() {
+ return Builder.node.apply(Builder, [tag].concat($A(arguments)));
+ }
+ });
+ }
+}
Added: modules/security/trunk/examples/seamspace/src/main/webapp/lightbox/bullet.gif
===================================================================
(Binary files differ)
Property changes on: modules/security/trunk/examples/seamspace/src/main/webapp/lightbox/bullet.gif
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: modules/security/trunk/examples/seamspace/src/main/webapp/lightbox/close.gif
===================================================================
(Binary files differ)
Property changes on: modules/security/trunk/examples/seamspace/src/main/webapp/lightbox/close.gif
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: modules/security/trunk/examples/seamspace/src/main/webapp/lightbox/closelabel.gif
===================================================================
(Binary files differ)
Property changes on: modules/security/trunk/examples/seamspace/src/main/webapp/lightbox/closelabel.gif
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: modules/security/trunk/examples/seamspace/src/main/webapp/lightbox/effects.js
===================================================================
--- modules/security/trunk/examples/seamspace/src/main/webapp/lightbox/effects.js (rev 0)
+++ modules/security/trunk/examples/seamspace/src/main/webapp/lightbox/effects.js 2010-03-25 02:33:21 UTC (rev 12264)
@@ -0,0 +1,1122 @@
+// script.aculo.us effects.js v1.8.1, Thu Jan 03 22:07:12 -0500 2008
+
+// Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
+// Contributors:
+// Justin Palmer (http://encytemedia.com/)
+// Mark Pilgrim (http://diveintomark.org/)
+// Martin Bialasinki
+//
+// script.aculo.us is freely distributable under the terms of an MIT-style license.
+// For details, see the script.aculo.us web site: http://script.aculo.us/
+
+// converts rgb() and #xxx to #xxxxxx format,
+// returns self (or first argument) if not convertable
+String.prototype.parseColor = function() {
+ var color = '#';
+ if (this.slice(0,4) == 'rgb(') {
+ var cols = this.slice(4,this.length-1).split(',');
+ var i=0; do { color += parseInt(cols[i]).toColorPart() } while (++i<3);
+ } else {
+ if (this.slice(0,1) == '#') {
+ if (this.length==4) for(var i=1;i<4;i++) color += (this.charAt(i) + this.charAt(i)).toLowerCase();
+ if (this.length==7) color = this.toLowerCase();
+ }
+ }
+ return (color.length==7 ? color : (arguments[0] || this));
+};
+
+/*--------------------------------------------------------------------------*/
+
+Element.collectTextNodes = function(element) {
+ return $A($(element).childNodes).collect( function(node) {
+ return (node.nodeType==3 ? node.nodeValue :
+ (node.hasChildNodes() ? Element.collectTextNodes(node) : ''));
+ }).flatten().join('');
+};
+
+Element.collectTextNodesIgnoreClass = function(element, className) {
+ return $A($(element).childNodes).collect( function(node) {
+ return (node.nodeType==3 ? node.nodeValue :
+ ((node.hasChildNodes() && !Element.hasClassName(node,className)) ?
+ Element.collectTextNodesIgnoreClass(node, className) : ''));
+ }).flatten().join('');
+};
+
+Element.setContentZoom = function(element, percent) {
+ element = $(element);
+ element.setStyle({fontSize: (percent/100) + 'em'});
+ if (Prototype.Browser.WebKit) window.scrollBy(0,0);
+ return element;
+};
+
+Element.getInlineOpacity = function(element){
+ return $(element).style.opacity || '';
+};
+
+Element.forceRerendering = function(element) {
+ try {
+ element = $(element);
+ var n = document.createTextNode(' ');
+ element.appendChild(n);
+ element.removeChild(n);
+ } catch(e) { }
+};
+
+/*--------------------------------------------------------------------------*/
+
+var Effect = {
+ _elementDoesNotExistError: {
+ name: 'ElementDoesNotExistError',
+ message: 'The specified DOM element does not exist, but is required for this effect to operate'
+ },
+ Transitions: {
+ linear: Prototype.K,
+ sinoidal: function(pos) {
+ return (-Math.cos(pos*Math.PI)/2) + 0.5;
+ },
+ reverse: function(pos) {
+ return 1-pos;
+ },
+ flicker: function(pos) {
+ var pos = ((-Math.cos(pos*Math.PI)/4) + 0.75) + Math.random()/4;
+ return pos > 1 ? 1 : pos;
+ },
+ wobble: function(pos) {
+ return (-Math.cos(pos*Math.PI*(9*pos))/2) + 0.5;
+ },
+ pulse: function(pos, pulses) {
+ pulses = pulses || 5;
+ return (
+ ((pos % (1/pulses)) * pulses).round() == 0 ?
+ ((pos * pulses * 2) - (pos * pulses * 2).floor()) :
+ 1 - ((pos * pulses * 2) - (pos * pulses * 2).floor())
+ );
+ },
+ spring: function(pos) {
+ return 1 - (Math.cos(pos * 4.5 * Math.PI) * Math.exp(-pos * 6));
+ },
+ none: function(pos) {
+ return 0;
+ },
+ full: function(pos) {
+ return 1;
+ }
+ },
+ DefaultOptions: {
+ duration: 1.0, // seconds
+ fps: 100, // 100= assume 66fps max.
+ sync: false, // true for combining
+ from: 0.0,
+ to: 1.0,
+ delay: 0.0,
+ queue: 'parallel'
+ },
+ tagifyText: function(element) {
+ var tagifyStyle = 'position:relative';
+ if (Prototype.Browser.IE) tagifyStyle += ';zoom:1';
+
+ element = $(element);
+ $A(element.childNodes).each( function(child) {
+ if (child.nodeType==3) {
+ child.nodeValue.toArray().each( function(character) {
+ element.insertBefore(
+ new Element('span', {style: tagifyStyle}).update(
+ character == ' ' ? String.fromCharCode(160) : character),
+ child);
+ });
+ Element.remove(child);
+ }
+ });
+ },
+ multiple: function(element, effect) {
+ var elements;
+ if (((typeof element == 'object') ||
+ Object.isFunction(element)) &&
+ (element.length))
+ elements = element;
+ else
+ elements = $(element).childNodes;
+
+ var options = Object.extend({
+ speed: 0.1,
+ delay: 0.0
+ }, arguments[2] || { });
+ var masterDelay = options.delay;
+
+ $A(elements).each( function(element, index) {
+ new effect(element, Object.extend(options, { delay: index * options.speed + masterDelay }));
+ });
+ },
+ PAIRS: {
+ 'slide': ['SlideDown','SlideUp'],
+ 'blind': ['BlindDown','BlindUp'],
+ 'appear': ['Appear','Fade']
+ },
+ toggle: function(element, effect) {
+ element = $(element);
+ effect = (effect || 'appear').toLowerCase();
+ var options = Object.extend({
+ queue: { position:'end', scope:(element.id || 'global'), limit: 1 }
+ }, arguments[2] || { });
+ Effect[element.visible() ?
+ Effect.PAIRS[effect][1] : Effect.PAIRS[effect][0]](element, options);
+ }
+};
+
+Effect.DefaultOptions.transition = Effect.Transitions.sinoidal;
+
+/* ------------- core effects ------------- */
+
+Effect.ScopedQueue = Class.create(Enumerable, {
+ initialize: function() {
+ this.effects = [];
+ this.interval = null;
+ },
+ _each: function(iterator) {
+ this.effects._each(iterator);
+ },
+ add: function(effect) {
+ var timestamp = new Date().getTime();
+
+ var position = Object.isString(effect.options.queue) ?
+ effect.options.queue : effect.options.queue.position;
+
+ switch(position) {
+ case 'front':
+ // move unstarted effects after this effect
+ this.effects.findAll(function(e){ return e.state=='idle' }).each( function(e) {
+ e.startOn += effect.finishOn;
+ e.finishOn += effect.finishOn;
+ });
+ break;
+ case 'with-last':
+ timestamp = this.effects.pluck('startOn').max() || timestamp;
+ break;
+ case 'end':
+ // start effect after last queued effect has finished
+ timestamp = this.effects.pluck('finishOn').max() || timestamp;
+ break;
+ }
+
+ effect.startOn += timestamp;
+ effect.finishOn += timestamp;
+
+ if (!effect.options.queue.limit || (this.effects.length < effect.options.queue.limit))
+ this.effects.push(effect);
+
+ if (!this.interval)
+ this.interval = setInterval(this.loop.bind(this), 15);
+ },
+ remove: function(effect) {
+ this.effects = this.effects.reject(function(e) { return e==effect });
+ if (this.effects.length == 0) {
+ clearInterval(this.interval);
+ this.interval = null;
+ }
+ },
+ loop: function() {
+ var timePos = new Date().getTime();
+ for(var i=0, len=this.effects.length;i<len;i++)
+ this.effects[i] && this.effects[i].loop(timePos);
+ }
+});
+
+Effect.Queues = {
+ instances: $H(),
+ get: function(queueName) {
+ if (!Object.isString(queueName)) return queueName;
+
+ return this.instances.get(queueName) ||
+ this.instances.set(queueName, new Effect.ScopedQueue());
+ }
+};
+Effect.Queue = Effect.Queues.get('global');
+
+Effect.Base = Class.create({
+ position: null,
+ start: function(options) {
+ function codeForEvent(options,eventName){
+ return (
+ (options[eventName+'Internal'] ? 'this.options.'+eventName+'Internal(this);' : '') +
+ (options[eventName] ? 'this.options.'+eventName+'(this);' : '')
+ );
+ }
+ if (options && options.transition === false) options.transition = Effect.Transitions.linear;
+ this.options = Object.extend(Object.extend({ },Effect.DefaultOptions), options || { });
+ this.currentFrame = 0;
+ this.state = 'idle';
+ this.startOn = this.options.delay*1000;
+ this.finishOn = this.startOn+(this.options.duration*1000);
+ this.fromToDelta = this.options.to-this.options.from;
+ this.totalTime = this.finishOn-this.startOn;
+ this.totalFrames = this.options.fps*this.options.duration;
+
+ eval('this.render = function(pos){ '+
+ 'if (this.state=="idle"){this.state="running";'+
+ codeForEvent(this.options,'beforeSetup')+
+ (this.setup ? 'this.setup();':'')+
+ codeForEvent(this.options,'afterSetup')+
+ '};if (this.state=="running"){'+
+ 'pos=this.options.transition(pos)*'+this.fromToDelta+'+'+this.options.from+';'+
+ 'this.position=pos;'+
+ codeForEvent(this.options,'beforeUpdate')+
+ (this.update ? 'this.update(pos);':'')+
+ codeForEvent(this.options,'afterUpdate')+
+ '}}');
+
+ this.event('beforeStart');
+ if (!this.options.sync)
+ Effect.Queues.get(Object.isString(this.options.queue) ?
+ 'global' : this.options.queue.scope).add(this);
+ },
+ loop: function(timePos) {
+ if (timePos >= this.startOn) {
+ if (timePos >= this.finishOn) {
+ this.render(1.0);
+ this.cancel();
+ this.event('beforeFinish');
+ if (this.finish) this.finish();
+ this.event('afterFinish');
+ return;
+ }
+ var pos = (timePos - this.startOn) / this.totalTime,
+ frame = (pos * this.totalFrames).round();
+ if (frame > this.currentFrame) {
+ this.render(pos);
+ this.currentFrame = frame;
+ }
+ }
+ },
+ cancel: function() {
+ if (!this.options.sync)
+ Effect.Queues.get(Object.isString(this.options.queue) ?
+ 'global' : this.options.queue.scope).remove(this);
+ this.state = 'finished';
+ },
+ event: function(eventName) {
+ if (this.options[eventName + 'Internal']) this.options[eventName + 'Internal'](this);
+ if (this.options[eventName]) this.options[eventName](this);
+ },
+ inspect: function() {
+ var data = $H();
+ for(property in this)
+ if (!Object.isFunction(this[property])) data.set(property, this[property]);
+ return '#<Effect:' + data.inspect() + ',options:' + $H(this.options).inspect() + '>';
+ }
+});
+
+Effect.Parallel = Class.create(Effect.Base, {
+ initialize: function(effects) {
+ this.effects = effects || [];
+ this.start(arguments[1]);
+ },
+ update: function(position) {
+ this.effects.invoke('render', position);
+ },
+ finish: function(position) {
+ this.effects.each( function(effect) {
+ effect.render(1.0);
+ effect.cancel();
+ effect.event('beforeFinish');
+ if (effect.finish) effect.finish(position);
+ effect.event('afterFinish');
+ });
+ }
+});
+
+Effect.Tween = Class.create(Effect.Base, {
+ initialize: function(object, from, to) {
+ object = Object.isString(object) ? $(object) : object;
+ var args = $A(arguments), method = args.last(),
+ options = args.length == 5 ? args[3] : null;
+ this.method = Object.isFunction(method) ? method.bind(object) :
+ Object.isFunction(object[method]) ? object[method].bind(object) :
+ function(value) { object[method] = value };
+ this.start(Object.extend({ from: from, to: to }, options || { }));
+ },
+ update: function(position) {
+ this.method(position);
+ }
+});
+
+Effect.Event = Class.create(Effect.Base, {
+ initialize: function() {
+ this.start(Object.extend({ duration: 0 }, arguments[0] || { }));
+ },
+ update: Prototype.emptyFunction
+});
+
+Effect.Opacity = Class.create(Effect.Base, {
+ initialize: function(element) {
+ this.element = $(element);
+ if (!this.element) throw(Effect._elementDoesNotExistError);
+ // make this work on IE on elements without 'layout'
+ if (Prototype.Browser.IE && (!this.element.currentStyle.hasLayout))
+ this.element.setStyle({zoom: 1});
+ var options = Object.extend({
+ from: this.element.getOpacity() || 0.0,
+ to: 1.0
+ }, arguments[1] || { });
+ this.start(options);
+ },
+ update: function(position) {
+ this.element.setOpacity(position);
+ }
+});
+
+Effect.Move = Class.create(Effect.Base, {
+ initialize: function(element) {
+ this.element = $(element);
+ if (!this.element) throw(Effect._elementDoesNotExistError);
+ var options = Object.extend({
+ x: 0,
+ y: 0,
+ mode: 'relative'
+ }, arguments[1] || { });
+ this.start(options);
+ },
+ setup: function() {
+ this.element.makePositioned();
+ this.originalLeft = parseFloat(this.element.getStyle('left') || '0');
+ this.originalTop = parseFloat(this.element.getStyle('top') || '0');
+ if (this.options.mode == 'absolute') {
+ this.options.x = this.options.x - this.originalLeft;
+ this.options.y = this.options.y - this.originalTop;
+ }
+ },
+ update: function(position) {
+ this.element.setStyle({
+ left: (this.options.x * position + this.originalLeft).round() + 'px',
+ top: (this.options.y * position + this.originalTop).round() + 'px'
+ });
+ }
+});
+
+// for backwards compatibility
+Effect.MoveBy = function(element, toTop, toLeft) {
+ return new Effect.Move(element,
+ Object.extend({ x: toLeft, y: toTop }, arguments[3] || { }));
+};
+
+Effect.Scale = Class.create(Effect.Base, {
+ initialize: function(element, percent) {
+ this.element = $(element);
+ if (!this.element) throw(Effect._elementDoesNotExistError);
+ var options = Object.extend({
+ scaleX: true,
+ scaleY: true,
+ scaleContent: true,
+ scaleFromCenter: false,
+ scaleMode: 'box', // 'box' or 'contents' or { } with provided values
+ scaleFrom: 100.0,
+ scaleTo: percent
+ }, arguments[2] || { });
+ this.start(options);
+ },
+ setup: function() {
+ this.restoreAfterFinish = this.options.restoreAfterFinish || false;
+ this.elementPositioning = this.element.getStyle('position');
+
+ this.originalStyle = { };
+ ['top','left','width','height','fontSize'].each( function(k) {
+ this.originalStyle[k] = this.element.style[k];
+ }.bind(this));
+
+ this.originalTop = this.element.offsetTop;
+ this.originalLeft = this.element.offsetLeft;
+
+ var fontSize = this.element.getStyle('font-size') || '100%';
+ ['em','px','%','pt'].each( function(fontSizeType) {
+ if (fontSize.indexOf(fontSizeType)>0) {
+ this.fontSize = parseFloat(fontSize);
+ this.fontSizeType = fontSizeType;
+ }
+ }.bind(this));
+
+ this.factor = (this.options.scaleTo - this.options.scaleFrom)/100;
+
+ this.dims = null;
+ if (this.options.scaleMode=='box')
+ this.dims = [this.element.offsetHeight, this.element.offsetWidth];
+ if (/^content/.test(this.options.scaleMode))
+ this.dims = [this.element.scrollHeight, this.element.scrollWidth];
+ if (!this.dims)
+ this.dims = [this.options.scaleMode.originalHeight,
+ this.options.scaleMode.originalWidth];
+ },
+ update: function(position) {
+ var currentScale = (this.options.scaleFrom/100.0) + (this.factor * position);
+ if (this.options.scaleContent && this.fontSize)
+ this.element.setStyle({fontSize: this.fontSize * currentScale + this.fontSizeType });
+ this.setDimensions(this.dims[0] * currentScale, this.dims[1] * currentScale);
+ },
+ finish: function(position) {
+ if (this.restoreAfterFinish) this.element.setStyle(this.originalStyle);
+ },
+ setDimensions: function(height, width) {
+ var d = { };
+ if (this.options.scaleX) d.width = width.round() + 'px';
+ if (this.options.scaleY) d.height = height.round() + 'px';
+ if (this.options.scaleFromCenter) {
+ var topd = (height - this.dims[0])/2;
+ var leftd = (width - this.dims[1])/2;
+ if (this.elementPositioning == 'absolute') {
+ if (this.options.scaleY) d.top = this.originalTop-topd + 'px';
+ if (this.options.scaleX) d.left = this.originalLeft-leftd + 'px';
+ } else {
+ if (this.options.scaleY) d.top = -topd + 'px';
+ if (this.options.scaleX) d.left = -leftd + 'px';
+ }
+ }
+ this.element.setStyle(d);
+ }
+});
+
+Effect.Highlight = Class.create(Effect.Base, {
+ initialize: function(element) {
+ this.element = $(element);
+ if (!this.element) throw(Effect._elementDoesNotExistError);
+ var options = Object.extend({ startcolor: '#ffff99' }, arguments[1] || { });
+ this.start(options);
+ },
+ setup: function() {
+ // Prevent executing on elements not in the layout flow
+ if (this.element.getStyle('display')=='none') { this.cancel(); return; }
+ // Disable background image during the effect
+ this.oldStyle = { };
+ if (!this.options.keepBackgroundImage) {
+ this.oldStyle.backgroundImage = this.element.getStyle('background-image');
+ this.element.setStyle({backgroundImage: 'none'});
+ }
+ if (!this.options.endcolor)
+ this.options.endcolor = this.element.getStyle('background-color').parseColor('#ffffff');
+ if (!this.options.restorecolor)
+ this.options.restorecolor = this.element.getStyle('background-color');
+ // init color calculations
+ this._base = $R(0,2).map(function(i){ return parseInt(this.options.startcolor.slice(i*2+1,i*2+3),16) }.bind(this));
+ this._delta = $R(0,2).map(function(i){ return parseInt(this.options.endcolor.slice(i*2+1,i*2+3),16)-this._base[i] }.bind(this));
+ },
+ update: function(position) {
+ this.element.setStyle({backgroundColor: $R(0,2).inject('#',function(m,v,i){
+ return m+((this._base[i]+(this._delta[i]*position)).round().toColorPart()); }.bind(this)) });
+ },
+ finish: function() {
+ this.element.setStyle(Object.extend(this.oldStyle, {
+ backgroundColor: this.options.restorecolor
+ }));
+ }
+});
+
+Effect.ScrollTo = function(element) {
+ var options = arguments[1] || { },
+ scrollOffsets = document.viewport.getScrollOffsets(),
+ elementOffsets = $(element).cumulativeOffset(),
+ max = (window.height || document.body.scrollHeight) - document.viewport.getHeight();
+
+ if (options.offset) elementOffsets[1] += options.offset;
+
+ return new Effect.Tween(null,
+ scrollOffsets.top,
+ elementOffsets[1] > max ? max : elementOffsets[1],
+ options,
+ function(p){ scrollTo(scrollOffsets.left, p.round()) }
+ );
+};
+
+/* ------------- combination effects ------------- */
+
+Effect.Fade = function(element) {
+ element = $(element);
+ var oldOpacity = element.getInlineOpacity();
+ var options = Object.extend({
+ from: element.getOpacity() || 1.0,
+ to: 0.0,
+ afterFinishInternal: function(effect) {
+ if (effect.options.to!=0) return;
+ effect.element.hide().setStyle({opacity: oldOpacity});
+ }
+ }, arguments[1] || { });
+ return new Effect.Opacity(element,options);
+};
+
+Effect.Appear = function(element) {
+ element = $(element);
+ var options = Object.extend({
+ from: (element.getStyle('display') == 'none' ? 0.0 : element.getOpacity() || 0.0),
+ to: 1.0,
+ // force Safari to render floated elements properly
+ afterFinishInternal: function(effect) {
+ effect.element.forceRerendering();
+ },
+ beforeSetup: function(effect) {
+ effect.element.setOpacity(effect.options.from).show();
+ }}, arguments[1] || { });
+ return new Effect.Opacity(element,options);
+};
+
+Effect.Puff = function(element) {
+ element = $(element);
+ var oldStyle = {
+ opacity: element.getInlineOpacity(),
+ position: element.getStyle('position'),
+ top: element.style.top,
+ left: element.style.left,
+ width: element.style.width,
+ height: element.style.height
+ };
+ return new Effect.Parallel(
+ [ new Effect.Scale(element, 200,
+ { sync: true, scaleFromCenter: true, scaleContent: true, restoreAfterFinish: true }),
+ new Effect.Opacity(element, { sync: true, to: 0.0 } ) ],
+ Object.extend({ duration: 1.0,
+ beforeSetupInternal: function(effect) {
+ Position.absolutize(effect.effects[0].element)
+ },
+ afterFinishInternal: function(effect) {
+ effect.effects[0].element.hide().setStyle(oldStyle); }
+ }, arguments[1] || { })
+ );
+};
+
+Effect.BlindUp = function(element) {
+ element = $(element);
+ element.makeClipping();
+ return new Effect.Scale(element, 0,
+ Object.extend({ scaleContent: false,
+ scaleX: false,
+ restoreAfterFinish: true,
+ afterFinishInternal: function(effect) {
+ effect.element.hide().undoClipping();
+ }
+ }, arguments[1] || { })
+ );
+};
+
+Effect.BlindDown = function(element) {
+ element = $(element);
+ var elementDimensions = element.getDimensions();
+ return new Effect.Scale(element, 100, Object.extend({
+ scaleContent: false,
+ scaleX: false,
+ scaleFrom: 0,
+ scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
+ restoreAfterFinish: true,
+ afterSetup: function(effect) {
+ effect.element.makeClipping().setStyle({height: '0px'}).show();
+ },
+ afterFinishInternal: function(effect) {
+ effect.element.undoClipping();
+ }
+ }, arguments[1] || { }));
+};
+
+Effect.SwitchOff = function(element) {
+ element = $(element);
+ var oldOpacity = element.getInlineOpacity();
+ return new Effect.Appear(element, Object.extend({
+ duration: 0.4,
+ from: 0,
+ transition: Effect.Transitions.flicker,
+ afterFinishInternal: function(effect) {
+ new Effect.Scale(effect.element, 1, {
+ duration: 0.3, scaleFromCenter: true,
+ scaleX: false, scaleContent: false, restoreAfterFinish: true,
+ beforeSetup: function(effect) {
+ effect.element.makePositioned().makeClipping();
+ },
+ afterFinishInternal: function(effect) {
+ effect.element.hide().undoClipping().undoPositioned().setStyle({opacity: oldOpacity});
+ }
+ })
+ }
+ }, arguments[1] || { }));
+};
+
+Effect.DropOut = function(element) {
+ element = $(element);
+ var oldStyle = {
+ top: element.getStyle('top'),
+ left: element.getStyle('left'),
+ opacity: element.getInlineOpacity() };
+ return new Effect.Parallel(
+ [ new Effect.Move(element, {x: 0, y: 100, sync: true }),
+ new Effect.Opacity(element, { sync: true, to: 0.0 }) ],
+ Object.extend(
+ { duration: 0.5,
+ beforeSetup: function(effect) {
+ effect.effects[0].element.makePositioned();
+ },
+ afterFinishInternal: function(effect) {
+ effect.effects[0].element.hide().undoPositioned().setStyle(oldStyle);
+ }
+ }, arguments[1] || { }));
+};
+
+Effect.Shake = function(element) {
+ element = $(element);
+ var options = Object.extend({
+ distance: 20,
+ duration: 0.5
+ }, arguments[1] || {});
+ var distance = parseFloat(options.distance);
+ var split = parseFloat(options.duration) / 10.0;
+ var oldStyle = {
+ top: element.getStyle('top'),
+ left: element.getStyle('left') };
+ return new Effect.Move(element,
+ { x: distance, y: 0, duration: split, afterFinishInternal: function(effect) {
+ new Effect.Move(effect.element,
+ { x: -distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) {
+ new Effect.Move(effect.element,
+ { x: distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) {
+ new Effect.Move(effect.element,
+ { x: -distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) {
+ new Effect.Move(effect.element,
+ { x: distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) {
+ new Effect.Move(effect.element,
+ { x: -distance, y: 0, duration: split, afterFinishInternal: function(effect) {
+ effect.element.undoPositioned().setStyle(oldStyle);
+ }}) }}) }}) }}) }}) }});
+};
+
+Effect.SlideDown = function(element) {
+ element = $(element).cleanWhitespace();
+ // SlideDown need to have the content of the element wrapped in a container element with fixed height!
+ var oldInnerBottom = element.down().getStyle('bottom');
+ var elementDimensions = element.getDimensions();
+ return new Effect.Scale(element, 100, Object.extend({
+ scaleContent: false,
+ scaleX: false,
+ scaleFrom: window.opera ? 0 : 1,
+ scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
+ restoreAfterFinish: true,
+ afterSetup: function(effect) {
+ effect.element.makePositioned();
+ effect.element.down().makePositioned();
+ if (window.opera) effect.element.setStyle({top: ''});
+ effect.element.makeClipping().setStyle({height: '0px'}).show();
+ },
+ afterUpdateInternal: function(effect) {
+ effect.element.down().setStyle({bottom:
+ (effect.dims[0] - effect.element.clientHeight) + 'px' });
+ },
+ afterFinishInternal: function(effect) {
+ effect.element.undoClipping().undoPositioned();
+ effect.element.down().undoPositioned().setStyle({bottom: oldInnerBottom}); }
+ }, arguments[1] || { })
+ );
+};
+
+Effect.SlideUp = function(element) {
+ element = $(element).cleanWhitespace();
+ var oldInnerBottom = element.down().getStyle('bottom');
+ var elementDimensions = element.getDimensions();
+ return new Effect.Scale(element, window.opera ? 0 : 1,
+ Object.extend({ scaleContent: false,
+ scaleX: false,
+ scaleMode: 'box',
+ scaleFrom: 100,
+ scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
+ restoreAfterFinish: true,
+ afterSetup: function(effect) {
+ effect.element.makePositioned();
+ effect.element.down().makePositioned();
+ if (window.opera) effect.element.setStyle({top: ''});
+ effect.element.makeClipping().show();
+ },
+ afterUpdateInternal: function(effect) {
+ effect.element.down().setStyle({bottom:
+ (effect.dims[0] - effect.element.clientHeight) + 'px' });
+ },
+ afterFinishInternal: function(effect) {
+ effect.element.hide().undoClipping().undoPositioned();
+ effect.element.down().undoPositioned().setStyle({bottom: oldInnerBottom});
+ }
+ }, arguments[1] || { })
+ );
+};
+
+// Bug in opera makes the TD containing this element expand for a instance after finish
+Effect.Squish = function(element) {
+ return new Effect.Scale(element, window.opera ? 1 : 0, {
+ restoreAfterFinish: true,
+ beforeSetup: function(effect) {
+ effect.element.makeClipping();
+ },
+ afterFinishInternal: function(effect) {
+ effect.element.hide().undoClipping();
+ }
+ });
+};
+
+Effect.Grow = function(element) {
+ element = $(element);
+ var options = Object.extend({
+ direction: 'center',
+ moveTransition: Effect.Transitions.sinoidal,
+ scaleTransition: Effect.Transitions.sinoidal,
+ opacityTransition: Effect.Transitions.full
+ }, arguments[1] || { });
+ var oldStyle = {
+ top: element.style.top,
+ left: element.style.left,
+ height: element.style.height,
+ width: element.style.width,
+ opacity: element.getInlineOpacity() };
+
+ var dims = element.getDimensions();
+ var initialMoveX, initialMoveY;
+ var moveX, moveY;
+
+ switch (options.direction) {
+ case 'top-left':
+ initialMoveX = initialMoveY = moveX = moveY = 0;
+ break;
+ case 'top-right':
+ initialMoveX = dims.width;
+ initialMoveY = moveY = 0;
+ moveX = -dims.width;
+ break;
+ case 'bottom-left':
+ initialMoveX = moveX = 0;
+ initialMoveY = dims.height;
+ moveY = -dims.height;
+ break;
+ case 'bottom-right':
+ initialMoveX = dims.width;
+ initialMoveY = dims.height;
+ moveX = -dims.width;
+ moveY = -dims.height;
+ break;
+ case 'center':
+ initialMoveX = dims.width / 2;
+ initialMoveY = dims.height / 2;
+ moveX = -dims.width / 2;
+ moveY = -dims.height / 2;
+ break;
+ }
+
+ return new Effect.Move(element, {
+ x: initialMoveX,
+ y: initialMoveY,
+ duration: 0.01,
+ beforeSetup: function(effect) {
+ effect.element.hide().makeClipping().makePositioned();
+ },
+ afterFinishInternal: function(effect) {
+ new Effect.Parallel(
+ [ new Effect.Opacity(effect.element, { sync: true, to: 1.0, from: 0.0, transition: options.opacityTransition }),
+ new Effect.Move(effect.element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }),
+ new Effect.Scale(effect.element, 100, {
+ scaleMode: { originalHeight: dims.height, originalWidth: dims.width },
+ sync: true, scaleFrom: window.opera ? 1 : 0, transition: options.scaleTransition, restoreAfterFinish: true})
+ ], Object.extend({
+ beforeSetup: function(effect) {
+ effect.effects[0].element.setStyle({height: '0px'}).show();
+ },
+ afterFinishInternal: function(effect) {
+ effect.effects[0].element.undoClipping().undoPositioned().setStyle(oldStyle);
+ }
+ }, options)
+ )
+ }
+ });
+};
+
+Effect.Shrink = function(element) {
+ element = $(element);
+ var options = Object.extend({
+ direction: 'center',
+ moveTransition: Effect.Transitions.sinoidal,
+ scaleTransition: Effect.Transitions.sinoidal,
+ opacityTransition: Effect.Transitions.none
+ }, arguments[1] || { });
+ var oldStyle = {
+ top: element.style.top,
+ left: element.style.left,
+ height: element.style.height,
+ width: element.style.width,
+ opacity: element.getInlineOpacity() };
+
+ var dims = element.getDimensions();
+ var moveX, moveY;
+
+ switch (options.direction) {
+ case 'top-left':
+ moveX = moveY = 0;
+ break;
+ case 'top-right':
+ moveX = dims.width;
+ moveY = 0;
+ break;
+ case 'bottom-left':
+ moveX = 0;
+ moveY = dims.height;
+ break;
+ case 'bottom-right':
+ moveX = dims.width;
+ moveY = dims.height;
+ break;
+ case 'center':
+ moveX = dims.width / 2;
+ moveY = dims.height / 2;
+ break;
+ }
+
+ return new Effect.Parallel(
+ [ new Effect.Opacity(element, { sync: true, to: 0.0, from: 1.0, transition: options.opacityTransition }),
+ new Effect.Scale(element, window.opera ? 1 : 0, { sync: true, transition: options.scaleTransition, restoreAfterFinish: true}),
+ new Effect.Move(element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition })
+ ], Object.extend({
+ beforeStartInternal: function(effect) {
+ effect.effects[0].element.makePositioned().makeClipping();
+ },
+ afterFinishInternal: function(effect) {
+ effect.effects[0].element.hide().undoClipping().undoPositioned().setStyle(oldStyle); }
+ }, options)
+ );
+};
+
+Effect.Pulsate = function(element) {
+ element = $(element);
+ var options = arguments[1] || { };
+ var oldOpacity = element.getInlineOpacity();
+ var transition = options.transition || Effect.Transitions.sinoidal;
+ var reverser = function(pos){ return transition(1-Effect.Transitions.pulse(pos, options.pulses)) };
+ reverser.bind(transition);
+ return new Effect.Opacity(element,
+ Object.extend(Object.extend({ duration: 2.0, from: 0,
+ afterFinishInternal: function(effect) { effect.element.setStyle({opacity: oldOpacity}); }
+ }, options), {transition: reverser}));
+};
+
+Effect.Fold = function(element) {
+ element = $(element);
+ var oldStyle = {
+ top: element.style.top,
+ left: element.style.left,
+ width: element.style.width,
+ height: element.style.height };
+ element.makeClipping();
+ return new Effect.Scale(element, 5, Object.extend({
+ scaleContent: false,
+ scaleX: false,
+ afterFinishInternal: function(effect) {
+ new Effect.Scale(element, 1, {
+ scaleContent: false,
+ scaleY: false,
+ afterFinishInternal: function(effect) {
+ effect.element.hide().undoClipping().setStyle(oldStyle);
+ } });
+ }}, arguments[1] || { }));
+};
+
+Effect.Morph = Class.create(Effect.Base, {
+ initialize: function(element) {
+ this.element = $(element);
+ if (!this.element) throw(Effect._elementDoesNotExistError);
+ var options = Object.extend({
+ style: { }
+ }, arguments[1] || { });
+
+ if (!Object.isString(options.style)) this.style = $H(options.style);
+ else {
+ if (options.style.include(':'))
+ this.style = options.style.parseStyle();
+ else {
+ this.element.addClassName(options.style);
+ this.style = $H(this.element.getStyles());
+ this.element.removeClassName(options.style);
+ var css = this.element.getStyles();
+ this.style = this.style.reject(function(style) {
+ return style.value == css[style.key];
+ });
+ options.afterFinishInternal = function(effect) {
+ effect.element.addClassName(effect.options.style);
+ effect.transforms.each(function(transform) {
+ effect.element.style[transform.style] = '';
+ });
+ }
+ }
+ }
+ this.start(options);
+ },
+
+ setup: function(){
+ function parseColor(color){
+ if (!color || ['rgba(0, 0, 0, 0)','transparent'].include(color)) color = '#ffffff';
+ color = color.parseColor();
+ return $R(0,2).map(function(i){
+ return parseInt( color.slice(i*2+1,i*2+3), 16 )
+ });
+ }
+ this.transforms = this.style.map(function(pair){
+ var property = pair[0], value = pair[1], unit = null;
+
+ if (value.parseColor('#zzzzzz') != '#zzzzzz') {
+ value = value.parseColor();
+ unit = 'color';
+ } else if (property == 'opacity') {
+ value = parseFloat(value);
+ if (Prototype.Browser.IE && (!this.element.currentStyle.hasLayout))
+ this.element.setStyle({zoom: 1});
+ } else if (Element.CSS_LENGTH.test(value)) {
+ var components = value.match(/^([\+\-]?[0-9\.]+)(.*)$/);
+ value = parseFloat(components[1]);
+ unit = (components.length == 3) ? components[2] : null;
+ }
+
+ var originalValue = this.element.getStyle(property);
+ return {
+ style: property.camelize(),
+ originalValue: unit=='color' ? parseColor(originalValue) : parseFloat(originalValue || 0),
+ targetValue: unit=='color' ? parseColor(value) : value,
+ unit: unit
+ };
+ }.bind(this)).reject(function(transform){
+ return (
+ (transform.originalValue == transform.targetValue) ||
+ (
+ transform.unit != 'color' &&
+ (isNaN(transform.originalValue) || isNaN(transform.targetValue))
+ )
+ )
+ });
+ },
+ update: function(position) {
+ var style = { }, transform, i = this.transforms.length;
+ while(i--)
+ style[(transform = this.transforms[i]).style] =
+ transform.unit=='color' ? '#'+
+ (Math.round(transform.originalValue[0]+
+ (transform.targetValue[0]-transform.originalValue[0])*position)).toColorPart() +
+ (Math.round(transform.originalValue[1]+
+ (transform.targetValue[1]-transform.originalValue[1])*position)).toColorPart() +
+ (Math.round(transform.originalValue[2]+
+ (transform.targetValue[2]-transform.originalValue[2])*position)).toColorPart() :
+ (transform.originalValue +
+ (transform.targetValue - transform.originalValue) * position).toFixed(3) +
+ (transform.unit === null ? '' : transform.unit);
+ this.element.setStyle(style, true);
+ }
+});
+
+Effect.Transform = Class.create({
+ initialize: function(tracks){
+ this.tracks = [];
+ this.options = arguments[1] || { };
+ this.addTracks(tracks);
+ },
+ addTracks: function(tracks){
+ tracks.each(function(track){
+ track = $H(track);
+ var data = track.values().first();
+ this.tracks.push($H({
+ ids: track.keys().first(),
+ effect: Effect.Morph,
+ options: { style: data }
+ }));
+ }.bind(this));
+ return this;
+ },
+ play: function(){
+ return new Effect.Parallel(
+ this.tracks.map(function(track){
+ var ids = track.get('ids'), effect = track.get('effect'), options = track.get('options');
+ var elements = [$(ids) || $$(ids)].flatten();
+ return elements.map(function(e){ return new effect(e, Object.extend({ sync:true }, options)) });
+ }).flatten(),
+ this.options
+ );
+ }
+});
+
+Element.CSS_PROPERTIES = $w(
+ 'backgroundColor backgroundPosition borderBottomColor borderBottomStyle ' +
+ 'borderBottomWidth borderLeftColor borderLeftStyle borderLeftWidth ' +
+ 'borderRightColor borderRightStyle borderRightWidth borderSpacing ' +
+ 'borderTopColor borderTopStyle borderTopWidth bottom clip color ' +
+ 'fontSize fontWeight height left letterSpacing lineHeight ' +
+ 'marginBottom marginLeft marginRight marginTop markerOffset maxHeight '+
+ 'maxWidth minHeight minWidth opacity outlineColor outlineOffset ' +
+ 'outlineWidth paddingBottom paddingLeft paddingRight paddingTop ' +
+ 'right textIndent top width wordSpacing zIndex');
+
+Element.CSS_LENGTH = /^(([\+\-]?[0-9\.]+)(em|ex|px|in|cm|mm|pt|pc|\%))|0$/;
+
+String.__parseStyleElement = document.createElement('div');
+String.prototype.parseStyle = function(){
+ var style, styleRules = $H();
+ if (Prototype.Browser.WebKit)
+ style = new Element('div',{style:this}).style;
+ else {
+ String.__parseStyleElement.innerHTML = '<div style="' + this + '"></div>';
+ style = String.__parseStyleElement.childNodes[0].style;
+ }
+
+ Element.CSS_PROPERTIES.each(function(property){
+ if (style[property]) styleRules.set(property, style[property]);
+ });
+
+ if (Prototype.Browser.IE && this.include('opacity'))
+ styleRules.set('opacity', this.match(/opacity:\s*((?:0|1)?(?:\.\d*)?)/)[1]);
+
+ return styleRules;
+};
+
+if (document.defaultView && document.defaultView.getComputedStyle) {
+ Element.getStyles = function(element) {
+ var css = document.defaultView.getComputedStyle($(element), null);
+ return Element.CSS_PROPERTIES.inject({ }, function(styles, property) {
+ styles[property] = css[property];
+ return styles;
+ });
+ };
+} else {
+ Element.getStyles = function(element) {
+ element = $(element);
+ var css = element.currentStyle, styles;
+ styles = Element.CSS_PROPERTIES.inject({ }, function(results, property) {
+ results[property] = css[property];
+ return results;
+ });
+ if (!styles.opacity) styles.opacity = element.getOpacity();
+ return styles;
+ };
+};
+
+Effect.Methods = {
+ morph: function(element, style) {
+ element = $(element);
+ new Effect.Morph(element, Object.extend({ style: style }, arguments[2] || { }));
+ return element;
+ },
+ visualEffect: function(element, effect, options) {
+ element = $(element)
+ var s = effect.dasherize().camelize(), klass = s.charAt(0).toUpperCase() + s.substring(1);
+ new Effect[klass](element, options);
+ return element;
+ },
+ highlight: function(element, options) {
+ element = $(element);
+ new Effect.Highlight(element, options);
+ return element;
+ }
+};
+
+$w('fade appear grow shrink fold blindUp blindDown slideUp slideDown '+
+ 'pulsate shake puff squish switchOff dropOut').each(
+ function(effect) {
+ Effect.Methods[effect] = function(element, options){
+ element = $(element);
+ Effect[effect.charAt(0).toUpperCase() + effect.substring(1)](element, options);
+ return element;
+ }
+ }
+);
+
+$w('getInlineOpacity forceRerendering setContentZoom collectTextNodes collectTextNodesIgnoreClass getStyles').each(
+ function(f) { Effect.Methods[f] = Element[f]; }
+);
+
+Element.addMethods(Effect.Methods);
Added: modules/security/trunk/examples/seamspace/src/main/webapp/lightbox/lightbox.css
===================================================================
--- modules/security/trunk/examples/seamspace/src/main/webapp/lightbox/lightbox.css (rev 0)
+++ modules/security/trunk/examples/seamspace/src/main/webapp/lightbox/lightbox.css 2010-03-25 02:33:21 UTC (rev 12264)
@@ -0,0 +1,27 @@
+#lightbox{ position: absolute; left: 0; width: 100%; z-index: 100; text-align: center; line-height: 0;}
+#lightbox img{ width: auto; height: auto;}
+#lightbox a img{ border: none; }
+
+#outerImageContainer{ position: relative; background-color: #fff; width: 250px; height: 250px; margin: 0 auto; }
+#imageContainer{ padding: 10px; }
+
+#loading{ position: absolute; top: 40%; left: 0%; height: 25%; width: 100%; text-align: center; line-height: 0; }
+#hoverNav{ position: absolute; top: 0; left: 0; height: 100%; width: 100%; z-index: 10; }
+#imageContainer>#hoverNav{ left: 0;}
+#hoverNav a{ outline: none;}
+
+#prevLink, #nextLink{ width: 49%; height: 100%; background-image: url(data:image/gif;base64,AAAA); /* Trick IE into showing hover */ display: block; }
+#prevLink { left: 0; float: left;}
+#nextLink { right: 0; float: right;}
+#prevLink:hover, #prevLink:visited:hover { background: url(prevlabel.gif) left 15% no-repeat; }
+#nextLink:hover, #nextLink:visited:hover { background: url(nextlabel.gif) right 15% no-repeat; }
+
+#imageDataContainer{ font: 10px Verdana, Helvetica, sans-serif; background-color: #fff; margin: 0 auto; line-height: 1.4em; overflow: auto; width: 100% ; }
+
+#imageData{ padding:0 10px; color: #666; }
+#imageData #imageDetails{ width: 70%; float: left; text-align: left; }
+#imageData #caption{ font-weight: bold; }
+#imageData #numberDisplay{ display: block; clear: left; padding-bottom: 1.0em; }
+#imageData #bottomNavClose{ width: 66px; float: right; padding-bottom: 0.7em; outline: none;}
+
+#overlay{ position: absolute; top: 0; left: 0; z-index: 90; width: 100%; height: 500px; background-color: #000; }
Added: modules/security/trunk/examples/seamspace/src/main/webapp/lightbox/lightbox.js
===================================================================
--- modules/security/trunk/examples/seamspace/src/main/webapp/lightbox/lightbox.js (rev 0)
+++ modules/security/trunk/examples/seamspace/src/main/webapp/lightbox/lightbox.js 2010-03-25 02:33:21 UTC (rev 12264)
@@ -0,0 +1,497 @@
+// -----------------------------------------------------------------------------------
+//
+// Lightbox v2.04
+// by Lokesh Dhakar - http://www.lokeshdhakar.com
+// Last Modification: 2/9/08
+//
+// For more information, visit:
+// http://lokeshdhakar.com/projects/lightbox2/
+//
+// Licensed under the Creative Commons Attribution 2.5 License - http://creativecommons.org/licenses/by/2.5/
+// - Free for use in both personal and commercial projects
+// - Attribution requires leaving author name, author link, and the license info intact.
+//
+// Thanks: Scott Upton(uptonic.com), Peter-Paul Koch(quirksmode.com), and Thomas Fuchs(mir.aculo.us) for ideas, libs, and snippets.
+// Artemy Tregubenko (arty.name) for cleanup and help in updating to latest ver of proto-aculous.
+//
+// -----------------------------------------------------------------------------------
+/*
+
+ Table of Contents
+ -----------------
+ Configuration
+
+ Lightbox Class Declaration
+ - initialize()
+ - updateImageList()
+ - start()
+ - changeImage()
+ - resizeImageContainer()
+ - showImage()
+ - updateDetails()
+ - updateNav()
+ - enableKeyboardNav()
+ - disableKeyboardNav()
+ - keyboardAction()
+ - preloadNeighborImages()
+ - end()
+
+ Function Calls
+ - document.observe()
+
+*/
+// -----------------------------------------------------------------------------------
+
+//
+// Configurationl
+//
+LightboxOptions = Object.extend({
+ fileLoadingImage: 'lightbox/loading.gif',
+ fileBottomNavCloseImage: 'lightbox/closelabel.gif',
+
+ overlayOpacity: 0.8, // controls transparency of shadow overlay
+
+ animate: true, // toggles resizing animations
+ resizeSpeed: 7, // controls the speed of the image resizing animations (1=slowest and 10=fastest)
+
+ borderSize: 10, //if you adjust the padding in the CSS, you will need to update this variable
+
+ // When grouping images this is used to write: Image # of #.
+ // Change it for non-english localization
+ labelImage: "Image",
+ labelOf: "of"
+}, window.LightboxOptions || {});
+
+// -----------------------------------------------------------------------------------
+
+var Lightbox = Class.create();
+
+Lightbox.prototype = {
+ imageArray: [],
+ activeImage: undefined,
+
+ // initialize()
+ // Constructor runs on completion of the DOM loading. Calls updateImageList and then
+ // the function inserts html at the bottom of the page which is used to display the shadow
+ // overlay and the image container.
+ //
+ initialize: function() {
+
+ this.updateImageList();
+
+ this.keyboardAction = this.keyboardAction.bindAsEventListener(this);
+
+ if (LightboxOptions.resizeSpeed > 10) LightboxOptions.resizeSpeed = 10;
+ if (LightboxOptions.resizeSpeed < 1) LightboxOptions.resizeSpeed = 1;
+
+ this.resizeDuration = LightboxOptions.animate ? ((11 - LightboxOptions.resizeSpeed) * 0.15) : 0;
+ this.overlayDuration = LightboxOptions.animate ? 0.2 : 0; // shadow fade in/out duration
+
+ // When Lightbox starts it will resize itself from 250 by 250 to the current image dimension.
+ // If animations are turned off, it will be hidden as to prevent a flicker of a
+ // white 250 by 250 box.
+ var size = (LightboxOptions.animate ? 250 : 1) + 'px';
+
+
+ // Code inserts html at the bottom of the page that looks similar to this:
+ //
+ // <div id="overlay"></div>
+ // <div id="lightbox">
+ // <div id="outerImageContainer">
+ // <div id="imageContainer">
+ // <img id="lightboxImage">
+ // <div style="" id="hoverNav">
+ // <a href="#" id="prevLink"></a>
+ // <a href="#" id="nextLink"></a>
+ // </div>
+ // <div id="loading">
+ // <a href="#" id="loadingLink">
+ // <img src="images/loading.gif">
+ // </a>
+ // </div>
+ // </div>
+ // </div>
+ // <div id="imageDataContainer">
+ // <div id="imageData">
+ // <div id="imageDetails">
+ // <span id="caption"></span>
+ // <span id="numberDisplay"></span>
+ // </div>
+ // <div id="bottomNav">
+ // <a href="#" id="bottomNavClose">
+ // <img src="images/close.gif">
+ // </a>
+ // </div>
+ // </div>
+ // </div>
+ // </div>
+
+
+ var objBody = $$('body')[0];
+
+ objBody.appendChild(Builder.node('div',{id:'overlay'}));
+
+ objBody.appendChild(Builder.node('div',{id:'lightbox'}, [
+ Builder.node('div',{id:'outerImageContainer'},
+ Builder.node('div',{id:'imageContainer'}, [
+ Builder.node('img',{id:'lightboxImage'}),
+ Builder.node('div',{id:'hoverNav'}, [
+ Builder.node('a',{id:'prevLink', href: '#' }),
+ Builder.node('a',{id:'nextLink', href: '#' })
+ ]),
+ Builder.node('div',{id:'loading'},
+ Builder.node('a',{id:'loadingLink', href: '#' },
+ Builder.node('img', {src: LightboxOptions.fileLoadingImage})
+ )
+ )
+ ])
+ ),
+ Builder.node('div', {id:'imageDataContainer'},
+ Builder.node('div',{id:'imageData'}, [
+ Builder.node('div',{id:'imageDetails'}, [
+ Builder.node('span',{id:'caption'}),
+ Builder.node('span',{id:'numberDisplay'})
+ ]),
+ Builder.node('div',{id:'bottomNav'},
+ Builder.node('a',{id:'bottomNavClose', href: '#' },
+ Builder.node('img', { src: LightboxOptions.fileBottomNavCloseImage })
+ )
+ )
+ ])
+ )
+ ]));
+
+
+ $('overlay').hide().observe('click', (function() { this.end(); }).bind(this));
+ $('lightbox').hide().observe('click', (function(event) { if (event.element().id == 'lightbox') this.end(); }).bind(this));
+ $('outerImageContainer').setStyle({ width: size, height: size });
+ $('prevLink').observe('click', (function(event) { event.stop(); this.changeImage(this.activeImage - 1); }).bindAsEventListener(this));
+ $('nextLink').observe('click', (function(event) { event.stop(); this.changeImage(this.activeImage + 1); }).bindAsEventListener(this));
+ $('loadingLink').observe('click', (function(event) { event.stop(); this.end(); }).bind(this));
+ $('bottomNavClose').observe('click', (function(event) { event.stop(); this.end(); }).bind(this));
+
+ var th = this;
+ (function(){
+ var ids =
+ 'overlay lightbox outerImageContainer imageContainer lightboxImage hoverNav prevLink nextLink loading loadingLink ' +
+ 'imageDataContainer imageData imageDetails caption numberDisplay bottomNav bottomNavClose';
+ $w(ids).each(function(id){ th[id] = $(id); });
+ }).defer();
+ },
+
+ //
+ // updateImageList()
+ // Loops through anchor tags looking for 'lightbox' references and applies onclick
+ // events to appropriate links. You can rerun after dynamically adding images w/ajax.
+ //
+ updateImageList: function() {
+ this.updateImageList = Prototype.emptyFunction;
+
+ document.observe('click', (function(event){
+ var target = event.findElement('a[rel^=lightbox]') || event.findElement('area[rel^=lightbox]');
+ if (target) {
+ event.stop();
+ this.start(target);
+ }
+ }).bind(this));
+ },
+
+ //
+ // start()
+ // Display overlay and lightbox. If image is part of a set, add siblings to imageArray.
+ //
+ start: function(imageLink) {
+
+ $$('select', 'object', 'embed').each(function(node){ node.style.visibility = 'hidden' });
+
+ // stretch overlay to fill page and fade in
+ var arrayPageSize = this.getPageSize();
+ $('overlay').setStyle({ width: arrayPageSize[0] + 'px', height: arrayPageSize[1] + 'px' });
+
+ new Effect.Appear(this.overlay, { duration: this.overlayDuration, from: 0.0, to: LightboxOptions.overlayOpacity });
+
+ this.imageArray = [];
+ var imageNum = 0;
+
+ if ((imageLink.rel == 'lightbox')){
+ // if image is NOT part of a set, add single image to imageArray
+ this.imageArray.push([imageLink.href, imageLink.title]);
+ } else {
+ // if image is part of a set..
+ this.imageArray =
+ $$(imageLink.tagName + '[href][rel="' + imageLink.rel + '"]').
+ collect(function(anchor){ return [anchor.href, anchor.title]; }).
+ uniq();
+
+ while (this.imageArray[imageNum][0] != imageLink.href) { imageNum++; }
+ }
+
+ // calculate top and left offset for the lightbox
+ var arrayPageScroll = document.viewport.getScrollOffsets();
+ var lightboxTop = arrayPageScroll[1] + (document.viewport.getHeight() / 10);
+ var lightboxLeft = arrayPageScroll[0];
+ this.lightbox.setStyle({ top: lightboxTop + 'px', left: lightboxLeft + 'px' }).show();
+
+ this.changeImage(imageNum);
+ },
+
+ //
+ // changeImage()
+ // Hide most elements and preload image in preparation for resizing image container.
+ //
+ changeImage: function(imageNum) {
+
+ this.activeImage = imageNum; // update global var
+
+ // hide elements during transition
+ if (LightboxOptions.animate) this.loading.show();
+ this.lightboxImage.hide();
+ this.hoverNav.hide();
+ this.prevLink.hide();
+ this.nextLink.hide();
+ // HACK: Opera9 does not currently support scriptaculous opacity and appear fx
+ this.imageDataContainer.setStyle({opacity: .0001});
+ this.numberDisplay.hide();
+
+ var imgPreloader = new Image();
+
+ // once image is preloaded, resize image container
+
+
+ imgPreloader.onload = (function(){
+ this.lightboxImage.src = this.imageArray[this.activeImage][0];
+ this.resizeImageContainer(imgPreloader.width, imgPreloader.height);
+ }).bind(this);
+ imgPreloader.src = this.imageArray[this.activeImage][0];
+ },
+
+ //
+ // resizeImageContainer()
+ //
+ resizeImageContainer: function(imgWidth, imgHeight) {
+
+ // get current width and height
+ var widthCurrent = this.outerImageContainer.getWidth();
+ var heightCurrent = this.outerImageContainer.getHeight();
+
+ // get new width and height
+ var widthNew = (imgWidth + LightboxOptions.borderSize * 2);
+ var heightNew = (imgHeight + LightboxOptions.borderSize * 2);
+
+ // scalars based on change from old to new
+ var xScale = (widthNew / widthCurrent) * 100;
+ var yScale = (heightNew / heightCurrent) * 100;
+
+ // calculate size difference between new and old image, and resize if necessary
+ var wDiff = widthCurrent - widthNew;
+ var hDiff = heightCurrent - heightNew;
+
+ if (hDiff != 0) new Effect.Scale(this.outerImageContainer, yScale, {scaleX: false, duration: this.resizeDuration, queue: 'front'});
+ if (wDiff != 0) new Effect.Scale(this.outerImageContainer, xScale, {scaleY: false, duration: this.resizeDuration, delay: this.resizeDuration});
+
+ // if new and old image are same size and no scaling transition is necessary,
+ // do a quick pause to prevent image flicker.
+ var timeout = 0;
+ if ((hDiff == 0) && (wDiff == 0)){
+ timeout = 100;
+ if (Prototype.Browser.IE) timeout = 250;
+ }
+
+ (function(){
+ this.prevLink.setStyle({ height: imgHeight + 'px' });
+ this.nextLink.setStyle({ height: imgHeight + 'px' });
+ this.imageDataContainer.setStyle({ width: widthNew + 'px' });
+
+ this.showImage();
+ }).bind(this).delay(timeout / 1000);
+ },
+
+ //
+ // showImage()
+ // Display image and begin preloading neighbors.
+ //
+ showImage: function(){
+ this.loading.hide();
+ new Effect.Appear(this.lightboxImage, {
+ duration: this.resizeDuration,
+ queue: 'end',
+ afterFinish: (function(){ this.updateDetails(); }).bind(this)
+ });
+ this.preloadNeighborImages();
+ },
+
+ //
+ // updateDetails()
+ // Display caption, image number, and bottom nav.
+ //
+ updateDetails: function() {
+
+ // if caption is not null
+// if (this.imageArray[this.activeImage][1] != ""){
+ this.caption.update(this.imageArray[this.activeImage][1]).show();
+// }
+
+ // if image is part of set display 'Image x of x'
+ if (this.imageArray.length > 1){
+ this.numberDisplay.update( LightboxOptions.labelImage + ' ' + (this.activeImage + 1) + ' ' + LightboxOptions.labelOf + ' ' + this.imageArray.length).show();
+ }
+
+ new Effect.Parallel(
+ [
+ new Effect.SlideDown(this.imageDataContainer, { sync: true, duration: this.resizeDuration, from: 0.0, to: 1.0 }),
+ new Effect.Appear(this.imageDataContainer, { sync: true, duration: this.resizeDuration })
+ ],
+ {
+ duration: this.resizeDuration,
+ afterFinish: (function() {
+ // update overlay size and update nav
+ var arrayPageSize = this.getPageSize();
+ this.overlay.setStyle({ height: arrayPageSize[1] + 'px' });
+ this.updateNav();
+ }).bind(this)
+ }
+ );
+ },
+
+ //
+ // updateNav()
+ // Display appropriate previous and next hover navigation.
+ //
+ updateNav: function() {
+
+ this.hoverNav.show();
+
+ // if not first image in set, display prev image button
+ if (this.activeImage > 0) this.prevLink.show();
+
+ // if not last image in set, display next image button
+ if (this.activeImage < (this.imageArray.length - 1)) this.nextLink.show();
+
+ this.enableKeyboardNav();
+ },
+
+ //
+ // enableKeyboardNav()
+ //
+ enableKeyboardNav: function() {
+ document.observe('keydown', this.keyboardAction);
+ },
+
+ //
+ // disableKeyboardNav()
+ //
+ disableKeyboardNav: function() {
+ document.stopObserving('keydown', this.keyboardAction);
+ },
+
+ //
+ // keyboardAction()
+ //
+ keyboardAction: function(event) {
+ var keycode = event.keyCode;
+
+ var escapeKey;
+ if (event.DOM_VK_ESCAPE) { // mozilla
+ escapeKey = event.DOM_VK_ESCAPE;
+ } else { // ie
+ escapeKey = 27;
+ }
+
+ var key = String.fromCharCode(keycode).toLowerCase();
+
+ if (key.match(/x|o|c/) || (keycode == escapeKey)){ // close lightbox
+ this.end();
+ } else if ((key == 'p') || (keycode == 37)){ // display previous image
+ if (this.activeImage != 0){
+ this.disableKeyboardNav();
+ this.changeImage(this.activeImage - 1);
+ }
+ } else if ((key == 'n') || (keycode == 39)){ // display next image
+ if (this.activeImage != (this.imageArray.length - 1)){
+ this.disableKeyboardNav();
+ this.changeImage(this.activeImage + 1);
+ }
+ }
+ },
+
+ //
+ // preloadNeighborImages()
+ // Preload previous and next images.
+ //
+ preloadNeighborImages: function(){
+ var preloadNextImage, preloadPrevImage;
+ if (this.imageArray.length > this.activeImage + 1){
+ preloadNextImage = new Image();
+ preloadNextImage.src = this.imageArray[this.activeImage + 1][0];
+ }
+ if (this.activeImage > 0){
+ preloadPrevImage = new Image();
+ preloadPrevImage.src = this.imageArray[this.activeImage - 1][0];
+ }
+
+ },
+
+ //
+ // end()
+ //
+ end: function() {
+ this.disableKeyboardNav();
+ this.lightbox.hide();
+ new Effect.Fade(this.overlay, { duration: this.overlayDuration });
+ $$('select', 'object', 'embed').each(function(node){ node.style.visibility = 'visible' });
+ },
+
+ //
+ // getPageSize()
+ //
+ getPageSize: function() {
+
+ var xScroll, yScroll;
+
+ if (window.innerHeight && window.scrollMaxY) {
+ xScroll = window.innerWidth + window.scrollMaxX;
+ yScroll = window.innerHeight + window.scrollMaxY;
+ } else if (document.body.scrollHeight > document.body.offsetHeight){ // all but Explorer Mac
+ xScroll = document.body.scrollWidth;
+ yScroll = document.body.scrollHeight;
+ } else { // Explorer Mac...would also work in Explorer 6 Strict, Mozilla and Safari
+ xScroll = document.body.offsetWidth;
+ yScroll = document.body.offsetHeight;
+ }
+
+ var windowWidth, windowHeight;
+
+ if (self.innerHeight) { // all except Explorer
+ if(document.documentElement.clientWidth){
+ windowWidth = document.documentElement.clientWidth;
+ } else {
+ windowWidth = self.innerWidth;
+ }
+ windowHeight = self.innerHeight;
+ } else if (document.documentElement && document.documentElement.clientHeight) { // Explorer 6 Strict Mode
+ windowWidth = document.documentElement.clientWidth;
+ windowHeight = document.documentElement.clientHeight;
+ } else if (document.body) { // other Explorers
+ windowWidth = document.body.clientWidth;
+ windowHeight = document.body.clientHeight;
+ }
+
+ // for small pages with total height less then height of the viewport
+ if(yScroll < windowHeight){
+ pageHeight = windowHeight;
+ } else {
+ pageHeight = yScroll;
+ }
+
+ // for small pages with total width less then width of the viewport
+ if(xScroll < windowWidth){
+ pageWidth = xScroll;
+ } else {
+ pageWidth = windowWidth;
+ }
+
+ return [pageWidth,pageHeight];
+ }
+}
+
+document.observe('dom:loaded', function () { new Lightbox(); });
\ No newline at end of file
Added: modules/security/trunk/examples/seamspace/src/main/webapp/lightbox/loading.gif
===================================================================
(Binary files differ)
Property changes on: modules/security/trunk/examples/seamspace/src/main/webapp/lightbox/loading.gif
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: modules/security/trunk/examples/seamspace/src/main/webapp/lightbox/nextlabel.gif
===================================================================
(Binary files differ)
Property changes on: modules/security/trunk/examples/seamspace/src/main/webapp/lightbox/nextlabel.gif
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: modules/security/trunk/examples/seamspace/src/main/webapp/lightbox/prevlabel.gif
===================================================================
(Binary files differ)
Property changes on: modules/security/trunk/examples/seamspace/src/main/webapp/lightbox/prevlabel.gif
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: modules/security/trunk/examples/seamspace/src/main/webapp/lightbox/prototype.js
===================================================================
--- modules/security/trunk/examples/seamspace/src/main/webapp/lightbox/prototype.js (rev 0)
+++ modules/security/trunk/examples/seamspace/src/main/webapp/lightbox/prototype.js 2010-03-25 02:33:21 UTC (rev 12264)
@@ -0,0 +1,4221 @@
+/* Prototype JavaScript framework, version 1.6.0.2
+ * (c) 2005-2008 Sam Stephenson
+ *
+ * Prototype is freely distributable under the terms of an MIT-style license.
+ * For details, see the Prototype web site: http://www.prototypejs.org/
+ *
+ *--------------------------------------------------------------------------*/
+
+var Prototype = {
+ Version: '1.6.0.2',
+
+ Browser: {
+ IE: !!(window.attachEvent && !window.opera),
+ Opera: !!window.opera,
+ WebKit: navigator.userAgent.indexOf('AppleWebKit/') > -1,
+ Gecko: navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('KHTML') == -1,
+ MobileSafari: !!navigator.userAgent.match(/Apple.*Mobile.*Safari/)
+ },
+
+ BrowserFeatures: {
+ XPath: !!document.evaluate,
+ ElementExtensions: !!window.HTMLElement,
+ SpecificElementExtensions:
+ document.createElement('div').__proto__ &&
+ document.createElement('div').__proto__ !==
+ document.createElement('form').__proto__
+ },
+
+ ScriptFragment: '<script[^>]*>([\\S\\s]*?)<\/script>',
+ JSONFilter: /^\/\*-secure-([\s\S]*)\*\/\s*$/,
+
+ emptyFunction: function() { },
+ K: function(x) { return x }
+};
+
+if (Prototype.Browser.MobileSafari)
+ Prototype.BrowserFeatures.SpecificElementExtensions = false;
+
+
+/* Based on Alex Arnell's inheritance implementation. */
+var Class = {
+ create: function() {
+ var parent = null, properties = $A(arguments);
+ if (Object.isFunction(properties[0]))
+ parent = properties.shift();
+
+ function klass() {
+ this.initialize.apply(this, arguments);
+ }
+
+ Object.extend(klass, Class.Methods);
+ klass.superclass = parent;
+ klass.subclasses = [];
+
+ if (parent) {
+ var subclass = function() { };
+ subclass.prototype = parent.prototype;
+ klass.prototype = new subclass;
+ parent.subclasses.push(klass);
+ }
+
+ for (var i = 0; i < properties.length; i++)
+ klass.addMethods(properties[i]);
+
+ if (!klass.prototype.initialize)
+ klass.prototype.initialize = Prototype.emptyFunction;
+
+ klass.prototype.constructor = klass;
+
+ return klass;
+ }
+};
+
+Class.Methods = {
+ addMethods: function(source) {
+ var ancestor = this.superclass && this.superclass.prototype;
+ var properties = Object.keys(source);
+
+ if (!Object.keys({ toString: true }).length)
+ properties.push("toString", "valueOf");
+
+ for (var i = 0, length = properties.length; i < length; i++) {
+ var property = properties[i], value = source[property];
+ if (ancestor && Object.isFunction(value) &&
+ value.argumentNames().first() == "$super") {
+ var method = value, value = Object.extend((function(m) {
+ return function() { return ancestor[m].apply(this, arguments) };
+ })(property).wrap(method), {
+ valueOf: function() { return method },
+ toString: function() { return method.toString() }
+ });
+ }
+ this.prototype[property] = value;
+ }
+
+ return this;
+ }
+};
+
+var Abstract = { };
+
+Object.extend = function(destination, source) {
+ for (var property in source)
+ destination[property] = source[property];
+ return destination;
+};
+
+Object.extend(Object, {
+ inspect: function(object) {
+ try {
+ if (Object.isUndefined(object)) return 'undefined';
+ if (object === null) return 'null';
+ return object.inspect ? object.inspect() : String(object);
+ } catch (e) {
+ if (e instanceof RangeError) return '...';
+ throw e;
+ }
+ },
+
+ toJSON: function(object) {
+ var type = typeof object;
+ switch (type) {
+ case 'undefined':
+ case 'function':
+ case 'unknown': return;
+ case 'boolean': return object.toString();
+ }
+
+ if (object === null) return 'null';
+ if (object.toJSON) return object.toJSON();
+ if (Object.isElement(object)) return;
+
+ var results = [];
+ for (var property in object) {
+ var value = Object.toJSON(object[property]);
+ if (!Object.isUndefined(value))
+ results.push(property.toJSON() + ': ' + value);
+ }
+
+ return '{' + results.join(', ') + '}';
+ },
+
+ toQueryString: function(object) {
+ return $H(object).toQueryString();
+ },
+
+ toHTML: function(object) {
+ return object && object.toHTML ? object.toHTML() : String.interpret(object);
+ },
+
+ keys: function(object) {
+ var keys = [];
+ for (var property in object)
+ keys.push(property);
+ return keys;
+ },
+
+ values: function(object) {
+ var values = [];
+ for (var property in object)
+ values.push(object[property]);
+ return values;
+ },
+
+ clone: function(object) {
+ return Object.extend({ }, object);
+ },
+
+ isElement: function(object) {
+ return object && object.nodeType == 1;
+ },
+
+ isArray: function(object) {
+ return object != null && typeof object == "object" &&
+ 'splice' in object && 'join' in object;
+ },
+
+ isHash: function(object) {
+ return object instanceof Hash;
+ },
+
+ isFunction: function(object) {
+ return typeof object == "function";
+ },
+
+ isString: function(object) {
+ return typeof object == "string";
+ },
+
+ isNumber: function(object) {
+ return typeof object == "number";
+ },
+
+ isUndefined: function(object) {
+ return typeof object == "undefined";
+ }
+});
+
+Object.extend(Function.prototype, {
+ argumentNames: function() {
+ var names = this.toString().match(/^[\s\(]*function[^(]*\((.*?)\)/)[1].split(",").invoke("strip");
+ return names.length == 1 && !names[0] ? [] : names;
+ },
+
+ bind: function() {
+ if (arguments.length < 2 && Object.isUndefined(arguments[0])) return this;
+ var __method = this, args = $A(arguments), object = args.shift();
+ return function() {
+ return __method.apply(object, args.concat($A(arguments)));
+ }
+ },
+
+ bindAsEventListener: function() {
+ var __method = this, args = $A(arguments), object = args.shift();
+ return function(event) {
+ return __method.apply(object, [event || window.event].concat(args));
+ }
+ },
+
+ curry: function() {
+ if (!arguments.length) return this;
+ var __method = this, args = $A(arguments);
+ return function() {
+ return __method.apply(this, args.concat($A(arguments)));
+ }
+ },
+
+ delay: function() {
+ var __method = this, args = $A(arguments), timeout = args.shift() * 1000;
+ return window.setTimeout(function() {
+ return __method.apply(__method, args);
+ }, timeout);
+ },
+
+ wrap: function(wrapper) {
+ var __method = this;
+ return function() {
+ return wrapper.apply(this, [__method.bind(this)].concat($A(arguments)));
+ }
+ },
+
+ methodize: function() {
+ if (this._methodized) return this._methodized;
+ var __method = this;
+ return this._methodized = function() {
+ return __method.apply(null, [this].concat($A(arguments)));
+ };
+ }
+});
+
+Function.prototype.defer = Function.prototype.delay.curry(0.01);
+
+Date.prototype.toJSON = function() {
+ return '"' + this.getUTCFullYear() + '-' +
+ (this.getUTCMonth() + 1).toPaddedString(2) + '-' +
+ this.getUTCDate().toPaddedString(2) + 'T' +
+ this.getUTCHours().toPaddedString(2) + ':' +
+ this.getUTCMinutes().toPaddedString(2) + ':' +
+ this.getUTCSeconds().toPaddedString(2) + 'Z"';
+};
+
+var Try = {
+ these: function() {
+ var returnValue;
+
+ for (var i = 0, length = arguments.length; i < length; i++) {
+ var lambda = arguments[i];
+ try {
+ returnValue = lambda();
+ break;
+ } catch (e) { }
+ }
+
+ return returnValue;
+ }
+};
+
+RegExp.prototype.match = RegExp.prototype.test;
+
+RegExp.escape = function(str) {
+ return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1');
+};
+
+/*--------------------------------------------------------------------------*/
+
+var PeriodicalExecuter = Class.create({
+ initialize: function(callback, frequency) {
+ this.callback = callback;
+ this.frequency = frequency;
+ this.currentlyExecuting = false;
+
+ this.registerCallback();
+ },
+
+ registerCallback: function() {
+ this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
+ },
+
+ execute: function() {
+ this.callback(this);
+ },
+
+ stop: function() {
+ if (!this.timer) return;
+ clearInterval(this.timer);
+ this.timer = null;
+ },
+
+ onTimerEvent: function() {
+ if (!this.currentlyExecuting) {
+ try {
+ this.currentlyExecuting = true;
+ this.execute();
+ } finally {
+ this.currentlyExecuting = false;
+ }
+ }
+ }
+});
+Object.extend(String, {
+ interpret: function(value) {
+ return value == null ? '' : String(value);
+ },
+ specialChar: {
+ '\b': '\\b',
+ '\t': '\\t',
+ '\n': '\\n',
+ '\f': '\\f',
+ '\r': '\\r',
+ '\\': '\\\\'
+ }
+});
+
+Object.extend(String.prototype, {
+ gsub: function(pattern, replacement) {
+ var result = '', source = this, match;
+ replacement = arguments.callee.prepareReplacement(replacement);
+
+ while (source.length > 0) {
+ if (match = source.match(pattern)) {
+ result += source.slice(0, match.index);
+ result += String.interpret(replacement(match));
+ source = source.slice(match.index + match[0].length);
+ } else {
+ result += source, source = '';
+ }
+ }
+ return result;
+ },
+
+ sub: function(pattern, replacement, count) {
+ replacement = this.gsub.prepareReplacement(replacement);
+ count = Object.isUndefined(count) ? 1 : count;
+
+ return this.gsub(pattern, function(match) {
+ if (--count < 0) return match[0];
+ return replacement(match);
+ });
+ },
+
+ scan: function(pattern, iterator) {
+ this.gsub(pattern, iterator);
+ return String(this);
+ },
+
+ truncate: function(length, truncation) {
+ length = length || 30;
+ truncation = Object.isUndefined(truncation) ? '...' : truncation;
+ return this.length > length ?
+ this.slice(0, length - truncation.length) + truncation : String(this);
+ },
+
+ strip: function() {
+ return this.replace(/^\s+/, '').replace(/\s+$/, '');
+ },
+
+ stripTags: function() {
+ return this.replace(/<\/?[^>]+>/gi, '');
+ },
+
+ stripScripts: function() {
+ return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), '');
+ },
+
+ extractScripts: function() {
+ var matchAll = new RegExp(Prototype.ScriptFragment, 'img');
+ var matchOne = new RegExp(Prototype.ScriptFragment, 'im');
+ return (this.match(matchAll) || []).map(function(scriptTag) {
+ return (scriptTag.match(matchOne) || ['', ''])[1];
+ });
+ },
+
+ evalScripts: function() {
+ return this.extractScripts().map(function(script) { return eval(script) });
+ },
+
+ escapeHTML: function() {
+ var self = arguments.callee;
+ self.text.data = this;
+ return self.div.innerHTML;
+ },
+
+ unescapeHTML: function() {
+ var div = new Element('div');
+ div.innerHTML = this.stripTags();
+ return div.childNodes[0] ? (div.childNodes.length > 1 ?
+ $A(div.childNodes).inject('', function(memo, node) { return memo+node.nodeValue }) :
+ div.childNodes[0].nodeValue) : '';
+ },
+
+ toQueryParams: function(separator) {
+ var match = this.strip().match(/([^?#]*)(#.*)?$/);
+ if (!match) return { };
+
+ return match[1].split(separator || '&').inject({ }, function(hash, pair) {
+ if ((pair = pair.split('='))[0]) {
+ var key = decodeURIComponent(pair.shift());
+ var value = pair.length > 1 ? pair.join('=') : pair[0];
+ if (value != undefined) value = decodeURIComponent(value);
+
+ if (key in hash) {
+ if (!Object.isArray(hash[key])) hash[key] = [hash[key]];
+ hash[key].push(value);
+ }
+ else hash[key] = value;
+ }
+ return hash;
+ });
+ },
+
+ toArray: function() {
+ return this.split('');
+ },
+
+ succ: function() {
+ return this.slice(0, this.length - 1) +
+ String.fromCharCode(this.charCodeAt(this.length - 1) + 1);
+ },
+
+ times: function(count) {
+ return count < 1 ? '' : new Array(count + 1).join(this);
+ },
+
+ camelize: function() {
+ var parts = this.split('-'), len = parts.length;
+ if (len == 1) return parts[0];
+
+ var camelized = this.charAt(0) == '-'
+ ? parts[0].charAt(0).toUpperCase() + parts[0].substring(1)
+ : parts[0];
+
+ for (var i = 1; i < len; i++)
+ camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1);
+
+ return camelized;
+ },
+
+ capitalize: function() {
+ return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase();
+ },
+
+ underscore: function() {
+ return this.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'#{1}_#{2}').gsub(/([a-z\d])([A-Z])/,'#{1}_#{2}').gsub(/-/,'_').toLowerCase();
+ },
+
+ dasherize: function() {
+ return this.gsub(/_/,'-');
+ },
+
+ inspect: function(useDoubleQuotes) {
+ var escapedString = this.gsub(/[\x00-\x1f\\]/, function(match) {
+ var character = String.specialChar[match[0]];
+ return character ? character : '\\u00' + match[0].charCodeAt().toPaddedString(2, 16);
+ });
+ if (useDoubleQuotes) return '"' + escapedString.replace(/"/g, '\\"') + '"';
+ return "'" + escapedString.replace(/'/g, '\\\'') + "'";
+ },
+
+ toJSON: function() {
+ return this.inspect(true);
+ },
+
+ unfilterJSON: function(filter) {
+ return this.sub(filter || Prototype.JSONFilter, '#{1}');
+ },
+
+ isJSON: function() {
+ var str = this;
+ if (str.blank()) return false;
+ str = this.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, '');
+ return (/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(str);
+ },
+
+ evalJSON: function(sanitize) {
+ var json = this.unfilterJSON();
+ try {
+ if (!sanitize || json.isJSON()) return eval('(' + json + ')');
+ } catch (e) { }
+ throw new SyntaxError('Badly formed JSON string: ' + this.inspect());
+ },
+
+ include: function(pattern) {
+ return this.indexOf(pattern) > -1;
+ },
+
+ startsWith: function(pattern) {
+ return this.indexOf(pattern) === 0;
+ },
+
+ endsWith: function(pattern) {
+ var d = this.length - pattern.length;
+ return d >= 0 && this.lastIndexOf(pattern) === d;
+ },
+
+ empty: function() {
+ return this == '';
+ },
+
+ blank: function() {
+ return /^\s*$/.test(this);
+ },
+
+ interpolate: function(object, pattern) {
+ return new Template(this, pattern).evaluate(object);
+ }
+});
+
+if (Prototype.Browser.WebKit || Prototype.Browser.IE) Object.extend(String.prototype, {
+ escapeHTML: function() {
+ return this.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>');
+ },
+ unescapeHTML: function() {
+ return this.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>');
+ }
+});
+
+String.prototype.gsub.prepareReplacement = function(replacement) {
+ if (Object.isFunction(replacement)) return replacement;
+ var template = new Template(replacement);
+ return function(match) { return template.evaluate(match) };
+};
+
+String.prototype.parseQuery = String.prototype.toQueryParams;
+
+Object.extend(String.prototype.escapeHTML, {
+ div: document.createElement('div'),
+ text: document.createTextNode('')
+});
+
+with (String.prototype.escapeHTML) div.appendChild(text);
+
+var Template = Class.create({
+ initialize: function(template, pattern) {
+ this.template = template.toString();
+ this.pattern = pattern || Template.Pattern;
+ },
+
+ evaluate: function(object) {
+ if (Object.isFunction(object.toTemplateReplacements))
+ object = object.toTemplateReplacements();
+
+ return this.template.gsub(this.pattern, function(match) {
+ if (object == null) return '';
+
+ var before = match[1] || '';
+ if (before == '\\') return match[2];
+
+ var ctx = object, expr = match[3];
+ var pattern = /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/;
+ match = pattern.exec(expr);
+ if (match == null) return before;
+
+ while (match != null) {
+ var comp = match[1].startsWith('[') ? match[2].gsub('\\\\]', ']') : match[1];
+ ctx = ctx[comp];
+ if (null == ctx || '' == match[3]) break;
+ expr = expr.substring('[' == match[3] ? match[1].length : match[0].length);
+ match = pattern.exec(expr);
+ }
+
+ return before + String.interpret(ctx);
+ });
+ }
+});
+Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;
+
+var $break = { };
+
+var Enumerable = {
+ each: function(iterator, context) {
+ var index = 0;
+ iterator = iterator.bind(context);
+ try {
+ this._each(function(value) {
+ iterator(value, index++);
+ });
+ } catch (e) {
+ if (e != $break) throw e;
+ }
+ return this;
+ },
+
+ eachSlice: function(number, iterator, context) {
+ iterator = iterator ? iterator.bind(context) : Prototype.K;
+ var index = -number, slices = [], array = this.toArray();
+ while ((index += number) < array.length)
+ slices.push(array.slice(index, index+number));
+ return slices.collect(iterator, context);
+ },
+
+ all: function(iterator, context) {
+ iterator = iterator ? iterator.bind(context) : Prototype.K;
+ var result = true;
+ this.each(function(value, index) {
+ result = result && !!iterator(value, index);
+ if (!result) throw $break;
+ });
+ return result;
+ },
+
+ any: function(iterator, context) {
+ iterator = iterator ? iterator.bind(context) : Prototype.K;
+ var result = false;
+ this.each(function(value, index) {
+ if (result = !!iterator(value, index))
+ throw $break;
+ });
+ return result;
+ },
+
+ collect: function(iterator, context) {
+ iterator = iterator ? iterator.bind(context) : Prototype.K;
+ var results = [];
+ this.each(function(value, index) {
+ results.push(iterator(value, index));
+ });
+ return results;
+ },
+
+ detect: function(iterator, context) {
+ iterator = iterator.bind(context);
+ var result;
+ this.each(function(value, index) {
+ if (iterator(value, index)) {
+ result = value;
+ throw $break;
+ }
+ });
+ return result;
+ },
+
+ findAll: function(iterator, context) {
+ iterator = iterator.bind(context);
+ var results = [];
+ this.each(function(value, index) {
+ if (iterator(value, index))
+ results.push(value);
+ });
+ return results;
+ },
+
+ grep: function(filter, iterator, context) {
+ iterator = iterator ? iterator.bind(context) : Prototype.K;
+ var results = [];
+
+ if (Object.isString(filter))
+ filter = new RegExp(filter);
+
+ this.each(function(value, index) {
+ if (filter.match(value))
+ results.push(iterator(value, index));
+ });
+ return results;
+ },
+
+ include: function(object) {
+ if (Object.isFunction(this.indexOf))
+ if (this.indexOf(object) != -1) return true;
+
+ var found = false;
+ this.each(function(value) {
+ if (value == object) {
+ found = true;
+ throw $break;
+ }
+ });
+ return found;
+ },
+
+ inGroupsOf: function(number, fillWith) {
+ fillWith = Object.isUndefined(fillWith) ? null : fillWith;
+ return this.eachSlice(number, function(slice) {
+ while(slice.length < number) slice.push(fillWith);
+ return slice;
+ });
+ },
+
+ inject: function(memo, iterator, context) {
+ iterator = iterator.bind(context);
+ this.each(function(value, index) {
+ memo = iterator(memo, value, index);
+ });
+ return memo;
+ },
+
+ invoke: function(method) {
+ var args = $A(arguments).slice(1);
+ return this.map(function(value) {
+ return value[method].apply(value, args);
+ });
+ },
+
+ max: function(iterator, context) {
+ iterator = iterator ? iterator.bind(context) : Prototype.K;
+ var result;
+ this.each(function(value, index) {
+ value = iterator(value, index);
+ if (result == null || value >= result)
+ result = value;
+ });
+ return result;
+ },
+
+ min: function(iterator, context) {
+ iterator = iterator ? iterator.bind(context) : Prototype.K;
+ var result;
+ this.each(function(value, index) {
+ value = iterator(value, index);
+ if (result == null || value < result)
+ result = value;
+ });
+ return result;
+ },
+
+ partition: function(iterator, context) {
+ iterator = iterator ? iterator.bind(context) : Prototype.K;
+ var trues = [], falses = [];
+ this.each(function(value, index) {
+ (iterator(value, index) ?
+ trues : falses).push(value);
+ });
+ return [trues, falses];
+ },
+
+ pluck: function(property) {
+ var results = [];
+ this.each(function(value) {
+ results.push(value[property]);
+ });
+ return results;
+ },
+
+ reject: function(iterator, context) {
+ iterator = iterator.bind(context);
+ var results = [];
+ this.each(function(value, index) {
+ if (!iterator(value, index))
+ results.push(value);
+ });
+ return results;
+ },
+
+ sortBy: function(iterator, context) {
+ iterator = iterator.bind(context);
+ return this.map(function(value, index) {
+ return {value: value, criteria: iterator(value, index)};
+ }).sort(function(left, right) {
+ var a = left.criteria, b = right.criteria;
+ return a < b ? -1 : a > b ? 1 : 0;
+ }).pluck('value');
+ },
+
+ toArray: function() {
+ return this.map();
+ },
+
+ zip: function() {
+ var iterator = Prototype.K, args = $A(arguments);
+ if (Object.isFunction(args.last()))
+ iterator = args.pop();
+
+ var collections = [this].concat(args).map($A);
+ return this.map(function(value, index) {
+ return iterator(collections.pluck(index));
+ });
+ },
+
+ size: function() {
+ return this.toArray().length;
+ },
+
+ inspect: function() {
+ return '#<Enumerable:' + this.toArray().inspect() + '>';
+ }
+};
+
+Object.extend(Enumerable, {
+ map: Enumerable.collect,
+ find: Enumerable.detect,
+ select: Enumerable.findAll,
+ filter: Enumerable.findAll,
+ member: Enumerable.include,
+ entries: Enumerable.toArray,
+ every: Enumerable.all,
+ some: Enumerable.any
+});
+function $A(iterable) {
+ if (!iterable) return [];
+ if (iterable.toArray) return iterable.toArray();
+ var length = iterable.length || 0, results = new Array(length);
+ while (length--) results[length] = iterable[length];
+ return results;
+}
+
+if (Prototype.Browser.WebKit) {
+ $A = function(iterable) {
+ if (!iterable) return [];
+ if (!(Object.isFunction(iterable) && iterable == '[object NodeList]') &&
+ iterable.toArray) return iterable.toArray();
+ var length = iterable.length || 0, results = new Array(length);
+ while (length--) results[length] = iterable[length];
+ return results;
+ };
+}
+
+Array.from = $A;
+
+Object.extend(Array.prototype, Enumerable);
+
+if (!Array.prototype._reverse) Array.prototype._reverse = Array.prototype.reverse;
+
+Object.extend(Array.prototype, {
+ _each: function(iterator) {
+ for (var i = 0, length = this.length; i < length; i++)
+ iterator(this[i]);
+ },
+
+ clear: function() {
+ this.length = 0;
+ return this;
+ },
+
+ first: function() {
+ return this[0];
+ },
+
+ last: function() {
+ return this[this.length - 1];
+ },
+
+ compact: function() {
+ return this.select(function(value) {
+ return value != null;
+ });
+ },
+
+ flatten: function() {
+ return this.inject([], function(array, value) {
+ return array.concat(Object.isArray(value) ?
+ value.flatten() : [value]);
+ });
+ },
+
+ without: function() {
+ var values = $A(arguments);
+ return this.select(function(value) {
+ return !values.include(value);
+ });
+ },
+
+ reverse: function(inline) {
+ return (inline !== false ? this : this.toArray())._reverse();
+ },
+
+ reduce: function() {
+ return this.length > 1 ? this : this[0];
+ },
+
+ uniq: function(sorted) {
+ return this.inject([], function(array, value, index) {
+ if (0 == index || (sorted ? array.last() != value : !array.include(value)))
+ array.push(value);
+ return array;
+ });
+ },
+
+ intersect: function(array) {
+ return this.uniq().findAll(function(item) {
+ return array.detect(function(value) { return item === value });
+ });
+ },
+
+ clone: function() {
+ return [].concat(this);
+ },
+
+ size: function() {
+ return this.length;
+ },
+
+ inspect: function() {
+ return '[' + this.map(Object.inspect).join(', ') + ']';
+ },
+
+ toJSON: function() {
+ var results = [];
+ this.each(function(object) {
+ var value = Object.toJSON(object);
+ if (!Object.isUndefined(value)) results.push(value);
+ });
+ return '[' + results.join(', ') + ']';
+ }
+});
+
+// use native browser JS 1.6 implementation if available
+if (Object.isFunction(Array.prototype.forEach))
+ Array.prototype._each = Array.prototype.forEach;
+
+if (!Array.prototype.indexOf) Array.prototype.indexOf = function(item, i) {
+ i || (i = 0);
+ var length = this.length;
+ if (i < 0) i = length + i;
+ for (; i < length; i++)
+ if (this[i] === item) return i;
+ return -1;
+};
+
+if (!Array.prototype.lastIndexOf) Array.prototype.lastIndexOf = function(item, i) {
+ i = isNaN(i) ? this.length : (i < 0 ? this.length + i : i) + 1;
+ var n = this.slice(0, i).reverse().indexOf(item);
+ return (n < 0) ? n : i - n - 1;
+};
+
+Array.prototype.toArray = Array.prototype.clone;
+
+function $w(string) {
+ if (!Object.isString(string)) return [];
+ string = string.strip();
+ return string ? string.split(/\s+/) : [];
+}
+
+if (Prototype.Browser.Opera){
+ Array.prototype.concat = function() {
+ var array = [];
+ for (var i = 0, length = this.length; i < length; i++) array.push(this[i]);
+ for (var i = 0, length = arguments.length; i < length; i++) {
+ if (Object.isArray(arguments[i])) {
+ for (var j = 0, arrayLength = arguments[i].length; j < arrayLength; j++)
+ array.push(arguments[i][j]);
+ } else {
+ array.push(arguments[i]);
+ }
+ }
+ return array;
+ };
+}
+Object.extend(Number.prototype, {
+ toColorPart: function() {
+ return this.toPaddedString(2, 16);
+ },
+
+ succ: function() {
+ return this + 1;
+ },
+
+ times: function(iterator) {
+ $R(0, this, true).each(iterator);
+ return this;
+ },
+
+ toPaddedString: function(length, radix) {
+ var string = this.toString(radix || 10);
+ return '0'.times(length - string.length) + string;
+ },
+
+ toJSON: function() {
+ return isFinite(this) ? this.toString() : 'null';
+ }
+});
+
+$w('abs round ceil floor').each(function(method){
+ Number.prototype[method] = Math[method].methodize();
+});
+function $H(object) {
+ return new Hash(object);
+};
+
+var Hash = Class.create(Enumerable, (function() {
+
+ function toQueryPair(key, value) {
+ if (Object.isUndefined(value)) return key;
+ return key + '=' + encodeURIComponent(String.interpret(value));
+ }
+
+ return {
+ initialize: function(object) {
+ this._object = Object.isHash(object) ? object.toObject() : Object.clone(object);
+ },
+
+ _each: function(iterator) {
+ for (var key in this._object) {
+ var value = this._object[key], pair = [key, value];
+ pair.key = key;
+ pair.value = value;
+ iterator(pair);
+ }
+ },
+
+ set: function(key, value) {
+ return this._object[key] = value;
+ },
+
+ get: function(key) {
+ return this._object[key];
+ },
+
+ unset: function(key) {
+ var value = this._object[key];
+ delete this._object[key];
+ return value;
+ },
+
+ toObject: function() {
+ return Object.clone(this._object);
+ },
+
+ keys: function() {
+ return this.pluck('key');
+ },
+
+ values: function() {
+ return this.pluck('value');
+ },
+
+ index: function(value) {
+ var match = this.detect(function(pair) {
+ return pair.value === value;
+ });
+ return match && match.key;
+ },
+
+ merge: function(object) {
+ return this.clone().update(object);
+ },
+
+ update: function(object) {
+ return new Hash(object).inject(this, function(result, pair) {
+ result.set(pair.key, pair.value);
+ return result;
+ });
+ },
+
+ toQueryString: function() {
+ return this.map(function(pair) {
+ var key = encodeURIComponent(pair.key), values = pair.value;
+
+ if (values && typeof values == 'object') {
+ if (Object.isArray(values))
+ return values.map(toQueryPair.curry(key)).join('&');
+ }
+ return toQueryPair(key, values);
+ }).join('&');
+ },
+
+ inspect: function() {
+ return '#<Hash:{' + this.map(function(pair) {
+ return pair.map(Object.inspect).join(': ');
+ }).join(', ') + '}>';
+ },
+
+ toJSON: function() {
+ return Object.toJSON(this.toObject());
+ },
+
+ clone: function() {
+ return new Hash(this);
+ }
+ }
+})());
+
+Hash.prototype.toTemplateReplacements = Hash.prototype.toObject;
+Hash.from = $H;
+var ObjectRange = Class.create(Enumerable, {
+ initialize: function(start, end, exclusive) {
+ this.start = start;
+ this.end = end;
+ this.exclusive = exclusive;
+ },
+
+ _each: function(iterator) {
+ var value = this.start;
+ while (this.include(value)) {
+ iterator(value);
+ value = value.succ();
+ }
+ },
+
+ include: function(value) {
+ if (value < this.start)
+ return false;
+ if (this.exclusive)
+ return value < this.end;
+ return value <= this.end;
+ }
+});
+
+var $R = function(start, end, exclusive) {
+ return new ObjectRange(start, end, exclusive);
+};
+
+var Ajax = {
+ getTransport: function() {
+ return Try.these(
+ function() {return new XMLHttpRequest()},
+ function() {return new ActiveXObject('Msxml2.XMLHTTP')},
+ function() {return new ActiveXObject('Microsoft.XMLHTTP')}
+ ) || false;
+ },
+
+ activeRequestCount: 0
+};
+
+Ajax.Responders = {
+ responders: [],
+
+ _each: function(iterator) {
+ this.responders._each(iterator);
+ },
+
+ register: function(responder) {
+ if (!this.include(responder))
+ this.responders.push(responder);
+ },
+
+ unregister: function(responder) {
+ this.responders = this.responders.without(responder);
+ },
+
+ dispatch: function(callback, request, transport, json) {
+ this.each(function(responder) {
+ if (Object.isFunction(responder[callback])) {
+ try {
+ responder[callback].apply(responder, [request, transport, json]);
+ } catch (e) { }
+ }
+ });
+ }
+};
+
+Object.extend(Ajax.Responders, Enumerable);
+
+Ajax.Responders.register({
+ onCreate: function() { Ajax.activeRequestCount++ },
+ onComplete: function() { Ajax.activeRequestCount-- }
+});
+
+Ajax.Base = Class.create({
+ initialize: function(options) {
+ this.options = {
+ method: 'post',
+ asynchronous: true,
+ contentType: 'application/x-www-form-urlencoded',
+ encoding: 'UTF-8',
+ parameters: '',
+ evalJSON: true,
+ evalJS: true
+ };
+ Object.extend(this.options, options || { });
+
+ this.options.method = this.options.method.toLowerCase();
+
+ if (Object.isString(this.options.parameters))
+ this.options.parameters = this.options.parameters.toQueryParams();
+ else if (Object.isHash(this.options.parameters))
+ this.options.parameters = this.options.parameters.toObject();
+ }
+});
+
+Ajax.Request = Class.create(Ajax.Base, {
+ _complete: false,
+
+ initialize: function($super, url, options) {
+ $super(options);
+ this.transport = Ajax.getTransport();
+ this.request(url);
+ },
+
+ request: function(url) {
+ this.url = url;
+ this.method = this.options.method;
+ var params = Object.clone(this.options.parameters);
+
+ if (!['get', 'post'].include(this.method)) {
+ // simulate other verbs over post
+ params['_method'] = this.method;
+ this.method = 'post';
+ }
+
+ this.parameters = params;
+
+ if (params = Object.toQueryString(params)) {
+ // when GET, append parameters to URL
+ if (this.method == 'get')
+ this.url += (this.url.include('?') ? '&' : '?') + params;
+ else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent))
+ params += '&_=';
+ }
+
+ try {
+ var response = new Ajax.Response(this);
+ if (this.options.onCreate) this.options.onCreate(response);
+ Ajax.Responders.dispatch('onCreate', this, response);
+
+ this.transport.open(this.method.toUpperCase(), this.url,
+ this.options.asynchronous);
+
+ if (this.options.asynchronous) this.respondToReadyState.bind(this).defer(1);
+
+ this.transport.onreadystatechange = this.onStateChange.bind(this);
+ this.setRequestHeaders();
+
+ this.body = this.method == 'post' ? (this.options.postBody || params) : null;
+ this.transport.send(this.body);
+
+ /* Force Firefox to handle ready state 4 for synchronous requests */
+ if (!this.options.asynchronous && this.transport.overrideMimeType)
+ this.onStateChange();
+
+ }
+ catch (e) {
+ this.dispatchException(e);
+ }
+ },
+
+ onStateChange: function() {
+ var readyState = this.transport.readyState;
+ if (readyState > 1 && !((readyState == 4) && this._complete))
+ this.respondToReadyState(this.transport.readyState);
+ },
+
+ setRequestHeaders: function() {
+ var headers = {
+ 'X-Requested-With': 'XMLHttpRequest',
+ 'X-Prototype-Version': Prototype.Version,
+ 'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'
+ };
+
+ if (this.method == 'post') {
+ headers['Content-type'] = this.options.contentType +
+ (this.options.encoding ? '; charset=' + this.options.encoding : '');
+
+ /* Force "Connection: close" for older Mozilla browsers to work
+ * around a bug where XMLHttpRequest sends an incorrect
+ * Content-length header. See Mozilla Bugzilla #246651.
+ */
+ if (this.transport.overrideMimeType &&
+ (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005)
+ headers['Connection'] = 'close';
+ }
+
+ // user-defined headers
+ if (typeof this.options.requestHeaders == 'object') {
+ var extras = this.options.requestHeaders;
+
+ if (Object.isFunction(extras.push))
+ for (var i = 0, length = extras.length; i < length; i += 2)
+ headers[extras[i]] = extras[i+1];
+ else
+ $H(extras).each(function(pair) { headers[pair.key] = pair.value });
+ }
+
+ for (var name in headers)
+ this.transport.setRequestHeader(name, headers[name]);
+ },
+
+ success: function() {
+ var status = this.getStatus();
+ return !status || (status >= 200 && status < 300);
+ },
+
+ getStatus: function() {
+ try {
+ return this.transport.status || 0;
+ } catch (e) { return 0 }
+ },
+
+ respondToReadyState: function(readyState) {
+ var state = Ajax.Request.Events[readyState], response = new Ajax.Response(this);
+
+ if (state == 'Complete') {
+ try {
+ this._complete = true;
+ (this.options['on' + response.status]
+ || this.options['on' + (this.success() ? 'Success' : 'Failure')]
+ || Prototype.emptyFunction)(response, response.headerJSON);
+ } catch (e) {
+ this.dispatchException(e);
+ }
+
+ var contentType = response.getHeader('Content-type');
+ if (this.options.evalJS == 'force'
+ || (this.options.evalJS && this.isSameOrigin() && contentType
+ && contentType.match(/^\s*(text|application)\/(x-)?(java|ecma)script(;.*)?\s*$/i)))
+ this.evalResponse();
+ }
+
+ try {
+ (this.options['on' + state] || Prototype.emptyFunction)(response, response.headerJSON);
+ Ajax.Responders.dispatch('on' + state, this, response, response.headerJSON);
+ } catch (e) {
+ this.dispatchException(e);
+ }
+
+ if (state == 'Complete') {
+ // avoid memory leak in MSIE: clean up
+ this.transport.onreadystatechange = Prototype.emptyFunction;
+ }
+ },
+
+ isSameOrigin: function() {
+ var m = this.url.match(/^\s*https?:\/\/[^\/]*/);
+ return !m || (m[0] == '#{protocol}//#{domain}#{port}'.interpolate({
+ protocol: location.protocol,
+ domain: document.domain,
+ port: location.port ? ':' + location.port : ''
+ }));
+ },
+
+ getHeader: function(name) {
+ try {
+ return this.transport.getResponseHeader(name) || null;
+ } catch (e) { return null }
+ },
+
+ evalResponse: function() {
+ try {
+ return eval((this.transport.responseText || '').unfilterJSON());
+ } catch (e) {
+ this.dispatchException(e);
+ }
+ },
+
+ dispatchException: function(exception) {
+ (this.options.onException || Prototype.emptyFunction)(this, exception);
+ Ajax.Responders.dispatch('onException', this, exception);
+ }
+});
+
+Ajax.Request.Events =
+ ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
+
+Ajax.Response = Class.create({
+ initialize: function(request){
+ this.request = request;
+ var transport = this.transport = request.transport,
+ readyState = this.readyState = transport.readyState;
+
+ if((readyState > 2 && !Prototype.Browser.IE) || readyState == 4) {
+ this.status = this.getStatus();
+ this.statusText = this.getStatusText();
+ this.responseText = String.interpret(transport.responseText);
+ this.headerJSON = this._getHeaderJSON();
+ }
+
+ if(readyState == 4) {
+ var xml = transport.responseXML;
+ this.responseXML = Object.isUndefined(xml) ? null : xml;
+ this.responseJSON = this._getResponseJSON();
+ }
+ },
+
+ status: 0,
+ statusText: '',
+
+ getStatus: Ajax.Request.prototype.getStatus,
+
+ getStatusText: function() {
+ try {
+ return this.transport.statusText || '';
+ } catch (e) { return '' }
+ },
+
+ getHeader: Ajax.Request.prototype.getHeader,
+
+ getAllHeaders: function() {
+ try {
+ return this.getAllResponseHeaders();
+ } catch (e) { return null }
+ },
+
+ getResponseHeader: function(name) {
+ return this.transport.getResponseHeader(name);
+ },
+
+ getAllResponseHeaders: function() {
+ return this.transport.getAllResponseHeaders();
+ },
+
+ _getHeaderJSON: function() {
+ var json = this.getHeader('X-JSON');
+ if (!json) return null;
+ json = decodeURIComponent(escape(json));
+ try {
+ return json.evalJSON(this.request.options.sanitizeJSON ||
+ !this.request.isSameOrigin());
+ } catch (e) {
+ this.request.dispatchException(e);
+ }
+ },
+
+ _getResponseJSON: function() {
+ var options = this.request.options;
+ if (!options.evalJSON || (options.evalJSON != 'force' &&
+ !(this.getHeader('Content-type') || '').include('application/json')) ||
+ this.responseText.blank())
+ return null;
+ try {
+ return this.responseText.evalJSON(options.sanitizeJSON ||
+ !this.request.isSameOrigin());
+ } catch (e) {
+ this.request.dispatchException(e);
+ }
+ }
+});
+
+Ajax.Updater = Class.create(Ajax.Request, {
+ initialize: function($super, container, url, options) {
+ this.container = {
+ success: (container.success || container),
+ failure: (container.failure || (container.success ? null : container))
+ };
+
+ options = Object.clone(options);
+ var onComplete = options.onComplete;
+ options.onComplete = (function(response, json) {
+ this.updateContent(response.responseText);
+ if (Object.isFunction(onComplete)) onComplete(response, json);
+ }).bind(this);
+
+ $super(url, options);
+ },
+
+ updateContent: function(responseText) {
+ var receiver = this.container[this.success() ? 'success' : 'failure'],
+ options = this.options;
+
+ if (!options.evalScripts) responseText = responseText.stripScripts();
+
+ if (receiver = $(receiver)) {
+ if (options.insertion) {
+ if (Object.isString(options.insertion)) {
+ var insertion = { }; insertion[options.insertion] = responseText;
+ receiver.insert(insertion);
+ }
+ else options.insertion(receiver, responseText);
+ }
+ else receiver.update(responseText);
+ }
+ }
+});
+
+Ajax.PeriodicalUpdater = Class.create(Ajax.Base, {
+ initialize: function($super, container, url, options) {
+ $super(options);
+ this.onComplete = this.options.onComplete;
+
+ this.frequency = (this.options.frequency || 2);
+ this.decay = (this.options.decay || 1);
+
+ this.updater = { };
+ this.container = container;
+ this.url = url;
+
+ this.start();
+ },
+
+ start: function() {
+ this.options.onComplete = this.updateComplete.bind(this);
+ this.onTimerEvent();
+ },
+
+ stop: function() {
+ this.updater.options.onComplete = undefined;
+ clearTimeout(this.timer);
+ (this.onComplete || Prototype.emptyFunction).apply(this, arguments);
+ },
+
+ updateComplete: function(response) {
+ if (this.options.decay) {
+ this.decay = (response.responseText == this.lastText ?
+ this.decay * this.options.decay : 1);
+
+ this.lastText = response.responseText;
+ }
+ this.timer = this.onTimerEvent.bind(this).delay(this.decay * this.frequency);
+ },
+
+ onTimerEvent: function() {
+ this.updater = new Ajax.Updater(this.container, this.url, this.options);
+ }
+});
+function $(element) {
+ if (arguments.length > 1) {
+ for (var i = 0, elements = [], length = arguments.length; i < length; i++)
+ elements.push($(arguments[i]));
+ return elements;
+ }
+ if (Object.isString(element))
+ element = document.getElementById(element);
+ return Element.extend(element);
+}
+
+if (Prototype.BrowserFeatures.XPath) {
+ document._getElementsByXPath = function(expression, parentElement) {
+ var results = [];
+ var query = document.evaluate(expression, $(parentElement) || document,
+ null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
+ for (var i = 0, length = query.snapshotLength; i < length; i++)
+ results.push(Element.extend(query.snapshotItem(i)));
+ return results;
+ };
+}
+
+/*--------------------------------------------------------------------------*/
+
+if (!window.Node) var Node = { };
+
+if (!Node.ELEMENT_NODE) {
+ // DOM level 2 ECMAScript Language Binding
+ Object.extend(Node, {
+ ELEMENT_NODE: 1,
+ ATTRIBUTE_NODE: 2,
+ TEXT_NODE: 3,
+ CDATA_SECTION_NODE: 4,
+ ENTITY_REFERENCE_NODE: 5,
+ ENTITY_NODE: 6,
+ PROCESSING_INSTRUCTION_NODE: 7,
+ COMMENT_NODE: 8,
+ DOCUMENT_NODE: 9,
+ DOCUMENT_TYPE_NODE: 10,
+ DOCUMENT_FRAGMENT_NODE: 11,
+ NOTATION_NODE: 12
+ });
+}
+
+(function() {
+ var element = this.Element;
+ this.Element = function(tagName, attributes) {
+ attributes = attributes || { };
+ tagName = tagName.toLowerCase();
+ var cache = Element.cache;
+ if (Prototype.Browser.IE && attributes.name) {
+ tagName = '<' + tagName + ' name="' + attributes.name + '">';
+ delete attributes.name;
+ return Element.writeAttribute(document.createElement(tagName), attributes);
+ }
+ if (!cache[tagName]) cache[tagName] = Element.extend(document.createElement(tagName));
+ return Element.writeAttribute(cache[tagName].cloneNode(false), attributes);
+ };
+ Object.extend(this.Element, element || { });
+}).call(window);
+
+Element.cache = { };
+
+Element.Methods = {
+ visible: function(element) {
+ return $(element).style.display != 'none';
+ },
+
+ toggle: function(element) {
+ element = $(element);
+ Element[Element.visible(element) ? 'hide' : 'show'](element);
+ return element;
+ },
+
+ hide: function(element) {
+ $(element).style.display = 'none';
+ return element;
+ },
+
+ show: function(element) {
+ $(element).style.display = '';
+ return element;
+ },
+
+ remove: function(element) {
+ element = $(element);
+ element.parentNode.removeChild(element);
+ return element;
+ },
+
+ update: function(element, content) {
+ element = $(element);
+ if (content && content.toElement) content = content.toElement();
+ if (Object.isElement(content)) return element.update().insert(content);
+ content = Object.toHTML(content);
+ element.innerHTML = content.stripScripts();
+ content.evalScripts.bind(content).defer();
+ return element;
+ },
+
+ replace: function(element, content) {
+ element = $(element);
+ if (content && content.toElement) content = content.toElement();
+ else if (!Object.isElement(content)) {
+ content = Object.toHTML(content);
+ var range = element.ownerDocument.createRange();
+ range.selectNode(element);
+ content.evalScripts.bind(content).defer();
+ content = range.createContextualFragment(content.stripScripts());
+ }
+ element.parentNode.replaceChild(content, element);
+ return element;
+ },
+
+ insert: function(element, insertions) {
+ element = $(element);
+
+ if (Object.isString(insertions) || Object.isNumber(insertions) ||
+ Object.isElement(insertions) || (insertions && (insertions.toElement || insertions.toHTML)))
+ insertions = {bottom:insertions};
+
+ var content, insert, tagName, childNodes;
+
+ for (var position in insertions) {
+ content = insertions[position];
+ position = position.toLowerCase();
+ insert = Element._insertionTranslations[position];
+
+ if (content && content.toElement) content = content.toElement();
+ if (Object.isElement(content)) {
+ insert(element, content);
+ continue;
+ }
+
+ content = Object.toHTML(content);
+
+ tagName = ((position == 'before' || position == 'after')
+ ? element.parentNode : element).tagName.toUpperCase();
+
+ childNodes = Element._getContentFromAnonymousElement(tagName, content.stripScripts());
+
+ if (position == 'top' || position == 'after') childNodes.reverse();
+ childNodes.each(insert.curry(element));
+
+ content.evalScripts.bind(content).defer();
+ }
+
+ return element;
+ },
+
+ wrap: function(element, wrapper, attributes) {
+ element = $(element);
+ if (Object.isElement(wrapper))
+ $(wrapper).writeAttribute(attributes || { });
+ else if (Object.isString(wrapper)) wrapper = new Element(wrapper, attributes);
+ else wrapper = new Element('div', wrapper);
+ if (element.parentNode)
+ element.parentNode.replaceChild(wrapper, element);
+ wrapper.appendChild(element);
+ return wrapper;
+ },
+
+ inspect: function(element) {
+ element = $(element);
+ var result = '<' + element.tagName.toLowerCase();
+ $H({'id': 'id', 'className': 'class'}).each(function(pair) {
+ var property = pair.first(), attribute = pair.last();
+ var value = (element[property] || '').toString();
+ if (value) result += ' ' + attribute + '=' + value.inspect(true);
+ });
+ return result + '>';
+ },
+
+ recursivelyCollect: function(element, property) {
+ element = $(element);
+ var elements = [];
+ while (element = element[property])
+ if (element.nodeType == 1)
+ elements.push(Element.extend(element));
+ return elements;
+ },
+
+ ancestors: function(element) {
+ return $(element).recursivelyCollect('parentNode');
+ },
+
+ descendants: function(element) {
+ return $(element).select("*");
+ },
+
+ firstDescendant: function(element) {
+ element = $(element).firstChild;
+ while (element && element.nodeType != 1) element = element.nextSibling;
+ return $(element);
+ },
+
+ immediateDescendants: function(element) {
+ if (!(element = $(element).firstChild)) return [];
+ while (element && element.nodeType != 1) element = element.nextSibling;
+ if (element) return [element].concat($(element).nextSiblings());
+ return [];
+ },
+
+ previousSiblings: function(element) {
+ return $(element).recursivelyCollect('previousSibling');
+ },
+
+ nextSiblings: function(element) {
+ return $(element).recursivelyCollect('nextSibling');
+ },
+
+ siblings: function(element) {
+ element = $(element);
+ return element.previousSiblings().reverse().concat(element.nextSiblings());
+ },
+
+ match: function(element, selector) {
+ if (Object.isString(selector))
+ selector = new Selector(selector);
+ return selector.match($(element));
+ },
+
+ up: function(element, expression, index) {
+ element = $(element);
+ if (arguments.length == 1) return $(element.parentNode);
+ var ancestors = element.ancestors();
+ return Object.isNumber(expression) ? ancestors[expression] :
+ Selector.findElement(ancestors, expression, index);
+ },
+
+ down: function(element, expression, index) {
+ element = $(element);
+ if (arguments.length == 1) return element.firstDescendant();
+ return Object.isNumber(expression) ? element.descendants()[expression] :
+ element.select(expression)[index || 0];
+ },
+
+ previous: function(element, expression, index) {
+ element = $(element);
+ if (arguments.length == 1) return $(Selector.handlers.previousElementSibling(element));
+ var previousSiblings = element.previousSiblings();
+ return Object.isNumber(expression) ? previousSiblings[expression] :
+ Selector.findElement(previousSiblings, expression, index);
+ },
+
+ next: function(element, expression, index) {
+ element = $(element);
+ if (arguments.length == 1) return $(Selector.handlers.nextElementSibling(element));
+ var nextSiblings = element.nextSiblings();
+ return Object.isNumber(expression) ? nextSiblings[expression] :
+ Selector.findElement(nextSiblings, expression, index);
+ },
+
+ select: function() {
+ var args = $A(arguments), element = $(args.shift());
+ return Selector.findChildElements(element, args);
+ },
+
+ adjacent: function() {
+ var args = $A(arguments), element = $(args.shift());
+ return Selector.findChildElements(element.parentNode, args).without(element);
+ },
+
+ identify: function(element) {
+ element = $(element);
+ var id = element.readAttribute('id'), self = arguments.callee;
+ if (id) return id;
+ do { id = 'anonymous_element_' + self.counter++ } while ($(id));
+ element.writeAttribute('id', id);
+ return id;
+ },
+
+ readAttribute: function(element, name) {
+ element = $(element);
+ if (Prototype.Browser.IE) {
+ var t = Element._attributeTranslations.read;
+ if (t.values[name]) return t.values[name](element, name);
+ if (t.names[name]) name = t.names[name];
+ if (name.include(':')) {
+ return (!element.attributes || !element.attributes[name]) ? null :
+ element.attributes[name].value;
+ }
+ }
+ return element.getAttribute(name);
+ },
+
+ writeAttribute: function(element, name, value) {
+ element = $(element);
+ var attributes = { }, t = Element._attributeTranslations.write;
+
+ if (typeof name == 'object') attributes = name;
+ else attributes[name] = Object.isUndefined(value) ? true : value;
+
+ for (var attr in attributes) {
+ name = t.names[attr] || attr;
+ value = attributes[attr];
+ if (t.values[attr]) name = t.values[attr](element, value);
+ if (value === false || value === null)
+ element.removeAttribute(name);
+ else if (value === true)
+ element.setAttribute(name, name);
+ else element.setAttribute(name, value);
+ }
+ return element;
+ },
+
+ getHeight: function(element) {
+ return $(element).getDimensions().height;
+ },
+
+ getWidth: function(element) {
+ return $(element).getDimensions().width;
+ },
+
+ classNames: function(element) {
+ return new Element.ClassNames(element);
+ },
+
+ hasClassName: function(element, className) {
+ if (!(element = $(element))) return;
+ var elementClassName = element.className;
+ return (elementClassName.length > 0 && (elementClassName == className ||
+ new RegExp("(^|\\s)" + className + "(\\s|$)").test(elementClassName)));
+ },
+
+ addClassName: function(element, className) {
+ if (!(element = $(element))) return;
+ if (!element.hasClassName(className))
+ element.className += (element.className ? ' ' : '') + className;
+ return element;
+ },
+
+ removeClassName: function(element, className) {
+ if (!(element = $(element))) return;
+ element.className = element.className.replace(
+ new RegExp("(^|\\s+)" + className + "(\\s+|$)"), ' ').strip();
+ return element;
+ },
+
+ toggleClassName: function(element, className) {
+ if (!(element = $(element))) return;
+ return element[element.hasClassName(className) ?
+ 'removeClassName' : 'addClassName'](className);
+ },
+
+ // removes whitespace-only text node children
+ cleanWhitespace: function(element) {
+ element = $(element);
+ var node = element.firstChild;
+ while (node) {
+ var nextNode = node.nextSibling;
+ if (node.nodeType == 3 && !/\S/.test(node.nodeValue))
+ element.removeChild(node);
+ node = nextNode;
+ }
+ return element;
+ },
+
+ empty: function(element) {
+ return $(element).innerHTML.blank();
+ },
+
+ descendantOf: function(element, ancestor) {
+ element = $(element), ancestor = $(ancestor);
+ var originalAncestor = ancestor;
+
+ if (element.compareDocumentPosition)
+ return (element.compareDocumentPosition(ancestor) & 8) === 8;
+
+ if (element.sourceIndex && !Prototype.Browser.Opera) {
+ var e = element.sourceIndex, a = ancestor.sourceIndex,
+ nextAncestor = ancestor.nextSibling;
+ if (!nextAncestor) {
+ do { ancestor = ancestor.parentNode; }
+ while (!(nextAncestor = ancestor.nextSibling) && ancestor.parentNode);
+ }
+ if (nextAncestor && nextAncestor.sourceIndex)
+ return (e > a && e < nextAncestor.sourceIndex);
+ }
+
+ while (element = element.parentNode)
+ if (element == originalAncestor) return true;
+ return false;
+ },
+
+ scrollTo: function(element) {
+ element = $(element);
+ var pos = element.cumulativeOffset();
+ window.scrollTo(pos[0], pos[1]);
+ return element;
+ },
+
+ getStyle: function(element, style) {
+ element = $(element);
+ style = style == 'float' ? 'cssFloat' : style.camelize();
+ var value = element.style[style];
+ if (!value) {
+ var css = document.defaultView.getComputedStyle(element, null);
+ value = css ? css[style] : null;
+ }
+ if (style == 'opacity') return value ? parseFloat(value) : 1.0;
+ return value == 'auto' ? null : value;
+ },
+
+ getOpacity: function(element) {
+ return $(element).getStyle('opacity');
+ },
+
+ setStyle: function(element, styles) {
+ element = $(element);
+ var elementStyle = element.style, match;
+ if (Object.isString(styles)) {
+ element.style.cssText += ';' + styles;
+ return styles.include('opacity') ?
+ element.setOpacity(styles.match(/opacity:\s*(\d?\.?\d*)/)[1]) : element;
+ }
+ for (var property in styles)
+ if (property == 'opacity') element.setOpacity(styles[property]);
+ else
+ elementStyle[(property == 'float' || property == 'cssFloat') ?
+ (Object.isUndefined(elementStyle.styleFloat) ? 'cssFloat' : 'styleFloat') :
+ property] = styles[property];
+
+ return element;
+ },
+
+ setOpacity: function(element, value) {
+ element = $(element);
+ element.style.opacity = (value == 1 || value === '') ? '' :
+ (value < 0.00001) ? 0 : value;
+ return element;
+ },
+
+ getDimensions: function(element) {
+ element = $(element);
+ var display = $(element).getStyle('display');
+ if (display != 'none' && display != null) // Safari bug
+ return {width: element.offsetWidth, height: element.offsetHeight};
+
+ // All *Width and *Height properties give 0 on elements with display none,
+ // so enable the element temporarily
+ var els = element.style;
+ var originalVisibility = els.visibility;
+ var originalPosition = els.position;
+ var originalDisplay = els.display;
+ els.visibility = 'hidden';
+ els.position = 'absolute';
+ els.display = 'block';
+ var originalWidth = element.clientWidth;
+ var originalHeight = element.clientHeight;
+ els.display = originalDisplay;
+ els.position = originalPosition;
+ els.visibility = originalVisibility;
+ return {width: originalWidth, height: originalHeight};
+ },
+
+ makePositioned: function(element) {
+ element = $(element);
+ var pos = Element.getStyle(element, 'position');
+ if (pos == 'static' || !pos) {
+ element._madePositioned = true;
+ element.style.position = 'relative';
+ // Opera returns the offset relative to the positioning context, when an
+ // element is position relative but top and left have not been defined
+ if (window.opera) {
+ element.style.top = 0;
+ element.style.left = 0;
+ }
+ }
+ return element;
+ },
+
+ undoPositioned: function(element) {
+ element = $(element);
+ if (element._madePositioned) {
+ element._madePositioned = undefined;
+ element.style.position =
+ element.style.top =
+ element.style.left =
+ element.style.bottom =
+ element.style.right = '';
+ }
+ return element;
+ },
+
+ makeClipping: function(element) {
+ element = $(element);
+ if (element._overflow) return element;
+ element._overflow = Element.getStyle(element, 'overflow') || 'auto';
+ if (element._overflow !== 'hidden')
+ element.style.overflow = 'hidden';
+ return element;
+ },
+
+ undoClipping: function(element) {
+ element = $(element);
+ if (!element._overflow) return element;
+ element.style.overflow = element._overflow == 'auto' ? '' : element._overflow;
+ element._overflow = null;
+ return element;
+ },
+
+ cumulativeOffset: function(element) {
+ var valueT = 0, valueL = 0;
+ do {
+ valueT += element.offsetTop || 0;
+ valueL += element.offsetLeft || 0;
+ element = element.offsetParent;
+ } while (element);
+ return Element._returnOffset(valueL, valueT);
+ },
+
+ positionedOffset: function(element) {
+ var valueT = 0, valueL = 0;
+ do {
+ valueT += element.offsetTop || 0;
+ valueL += element.offsetLeft || 0;
+ element = element.offsetParent;
+ if (element) {
+ if (element.tagName == 'BODY') break;
+ var p = Element.getStyle(element, 'position');
+ if (p !== 'static') break;
+ }
+ } while (element);
+ return Element._returnOffset(valueL, valueT);
+ },
+
+ absolutize: function(element) {
+ element = $(element);
+ if (element.getStyle('position') == 'absolute') return;
+ // Position.prepare(); // To be done manually by Scripty when it needs it.
+
+ var offsets = element.positionedOffset();
+ var top = offsets[1];
+ var left = offsets[0];
+ var width = element.clientWidth;
+ var height = element.clientHeight;
+
+ element._originalLeft = left - parseFloat(element.style.left || 0);
+ element._originalTop = top - parseFloat(element.style.top || 0);
+ element._originalWidth = element.style.width;
+ element._originalHeight = element.style.height;
+
+ element.style.position = 'absolute';
+ element.style.top = top + 'px';
+ element.style.left = left + 'px';
+ element.style.width = width + 'px';
+ element.style.height = height + 'px';
+ return element;
+ },
+
+ relativize: function(element) {
+ element = $(element);
+ if (element.getStyle('position') == 'relative') return;
+ // Position.prepare(); // To be done manually by Scripty when it needs it.
+
+ element.style.position = 'relative';
+ var top = parseFloat(element.style.top || 0) - (element._originalTop || 0);
+ var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0);
+
+ element.style.top = top + 'px';
+ element.style.left = left + 'px';
+ element.style.height = element._originalHeight;
+ element.style.width = element._originalWidth;
+ return element;
+ },
+
+ cumulativeScrollOffset: function(element) {
+ var valueT = 0, valueL = 0;
+ do {
+ valueT += element.scrollTop || 0;
+ valueL += element.scrollLeft || 0;
+ element = element.parentNode;
+ } while (element);
+ return Element._returnOffset(valueL, valueT);
+ },
+
+ getOffsetParent: function(element) {
+ if (element.offsetParent) return $(element.offsetParent);
+ if (element == document.body) return $(element);
+
+ while ((element = element.parentNode) && element != document.body)
+ if (Element.getStyle(element, 'position') != 'static')
+ return $(element);
+
+ return $(document.body);
+ },
+
+ viewportOffset: function(forElement) {
+ var valueT = 0, valueL = 0;
+
+ var element = forElement;
+ do {
+ valueT += element.offsetTop || 0;
+ valueL += element.offsetLeft || 0;
+
+ // Safari fix
+ if (element.offsetParent == document.body &&
+ Element.getStyle(element, 'position') == 'absolute') break;
+
+ } while (element = element.offsetParent);
+
+ element = forElement;
+ do {
+ if (!Prototype.Browser.Opera || element.tagName == 'BODY') {
+ valueT -= element.scrollTop || 0;
+ valueL -= element.scrollLeft || 0;
+ }
+ } while (element = element.parentNode);
+
+ return Element._returnOffset(valueL, valueT);
+ },
+
+ clonePosition: function(element, source) {
+ var options = Object.extend({
+ setLeft: true,
+ setTop: true,
+ setWidth: true,
+ setHeight: true,
+ offsetTop: 0,
+ offsetLeft: 0
+ }, arguments[2] || { });
+
+ // find page position of source
+ source = $(source);
+ var p = source.viewportOffset();
+
+ // find coordinate system to use
+ element = $(element);
+ var delta = [0, 0];
+ var parent = null;
+ // delta [0,0] will do fine with position: fixed elements,
+ // position:absolute needs offsetParent deltas
+ if (Element.getStyle(element, 'position') == 'absolute') {
+ parent = element.getOffsetParent();
+ delta = parent.viewportOffset();
+ }
+
+ // correct by body offsets (fixes Safari)
+ if (parent == document.body) {
+ delta[0] -= document.body.offsetLeft;
+ delta[1] -= document.body.offsetTop;
+ }
+
+ // set position
+ if (options.setLeft) element.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px';
+ if (options.setTop) element.style.top = (p[1] - delta[1] + options.offsetTop) + 'px';
+ if (options.setWidth) element.style.width = source.offsetWidth + 'px';
+ if (options.setHeight) element.style.height = source.offsetHeight + 'px';
+ return element;
+ }
+};
+
+Element.Methods.identify.counter = 1;
+
+Object.extend(Element.Methods, {
+ getElementsBySelector: Element.Methods.select,
+ childElements: Element.Methods.immediateDescendants
+});
+
+Element._attributeTranslations = {
+ write: {
+ names: {
+ className: 'class',
+ htmlFor: 'for'
+ },
+ values: { }
+ }
+};
+
+if (Prototype.Browser.Opera) {
+ Element.Methods.getStyle = Element.Methods.getStyle.wrap(
+ function(proceed, element, style) {
+ switch (style) {
+ case 'left': case 'top': case 'right': case 'bottom':
+ if (proceed(element, 'position') === 'static') return null;
+ case 'height': case 'width':
+ // returns '0px' for hidden elements; we want it to return null
+ if (!Element.visible(element)) return null;
+
+ // returns the border-box dimensions rather than the content-box
+ // dimensions, so we subtract padding and borders from the value
+ var dim = parseInt(proceed(element, style), 10);
+
+ if (dim !== element['offset' + style.capitalize()])
+ return dim + 'px';
+
+ var properties;
+ if (style === 'height') {
+ properties = ['border-top-width', 'padding-top',
+ 'padding-bottom', 'border-bottom-width'];
+ }
+ else {
+ properties = ['border-left-width', 'padding-left',
+ 'padding-right', 'border-right-width'];
+ }
+ return properties.inject(dim, function(memo, property) {
+ var val = proceed(element, property);
+ return val === null ? memo : memo - parseInt(val, 10);
+ }) + 'px';
+ default: return proceed(element, style);
+ }
+ }
+ );
+
+ Element.Methods.readAttribute = Element.Methods.readAttribute.wrap(
+ function(proceed, element, attribute) {
+ if (attribute === 'title') return element.title;
+ return proceed(element, attribute);
+ }
+ );
+}
+
+else if (Prototype.Browser.IE) {
+ // IE doesn't report offsets correctly for static elements, so we change them
+ // to "relative" to get the values, then change them back.
+ Element.Methods.getOffsetParent = Element.Methods.getOffsetParent.wrap(
+ function(proceed, element) {
+ element = $(element);
+ var position = element.getStyle('position');
+ if (position !== 'static') return proceed(element);
+ element.setStyle({ position: 'relative' });
+ var value = proceed(element);
+ element.setStyle({ position: position });
+ return value;
+ }
+ );
+
+ $w('positionedOffset viewportOffset').each(function(method) {
+ Element.Methods[method] = Element.Methods[method].wrap(
+ function(proceed, element) {
+ element = $(element);
+ var position = element.getStyle('position');
+ if (position !== 'static') return proceed(element);
+ // Trigger hasLayout on the offset parent so that IE6 reports
+ // accurate offsetTop and offsetLeft values for position: fixed.
+ var offsetParent = element.getOffsetParent();
+ if (offsetParent && offsetParent.getStyle('position') === 'fixed')
+ offsetParent.setStyle({ zoom: 1 });
+ element.setStyle({ position: 'relative' });
+ var value = proceed(element);
+ element.setStyle({ position: position });
+ return value;
+ }
+ );
+ });
+
+ Element.Methods.getStyle = function(element, style) {
+ element = $(element);
+ style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize();
+ var value = element.style[style];
+ if (!value && element.currentStyle) value = element.currentStyle[style];
+
+ if (style == 'opacity') {
+ if (value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/))
+ if (value[1]) return parseFloat(value[1]) / 100;
+ return 1.0;
+ }
+
+ if (value == 'auto') {
+ if ((style == 'width' || style == 'height') && (element.getStyle('display') != 'none'))
+ return element['offset' + style.capitalize()] + 'px';
+ return null;
+ }
+ return value;
+ };
+
+ Element.Methods.setOpacity = function(element, value) {
+ function stripAlpha(filter){
+ return filter.replace(/alpha\([^\)]*\)/gi,'');
+ }
+ element = $(element);
+ var currentStyle = element.currentStyle;
+ if ((currentStyle && !currentStyle.hasLayout) ||
+ (!currentStyle && element.style.zoom == 'normal'))
+ element.style.zoom = 1;
+
+ var filter = element.getStyle('filter'), style = element.style;
+ if (value == 1 || value === '') {
+ (filter = stripAlpha(filter)) ?
+ style.filter = filter : style.removeAttribute('filter');
+ return element;
+ } else if (value < 0.00001) value = 0;
+ style.filter = stripAlpha(filter) +
+ 'alpha(opacity=' + (value * 100) + ')';
+ return element;
+ };
+
+ Element._attributeTranslations = {
+ read: {
+ names: {
+ 'class': 'className',
+ 'for': 'htmlFor'
+ },
+ values: {
+ _getAttr: function(element, attribute) {
+ return element.getAttribute(attribute, 2);
+ },
+ _getAttrNode: function(element, attribute) {
+ var node = element.getAttributeNode(attribute);
+ return node ? node.value : "";
+ },
+ _getEv: function(element, attribute) {
+ attribute = element.getAttribute(attribute);
+ return attribute ? attribute.toString().slice(23, -2) : null;
+ },
+ _flag: function(element, attribute) {
+ return $(element).hasAttribute(attribute) ? attribute : null;
+ },
+ style: function(element) {
+ return element.style.cssText.toLowerCase();
+ },
+ title: function(element) {
+ return element.title;
+ }
+ }
+ }
+ };
+
+ Element._attributeTranslations.write = {
+ names: Object.extend({
+ cellpadding: 'cellPadding',
+ cellspacing: 'cellSpacing'
+ }, Element._attributeTranslations.read.names),
+ values: {
+ checked: function(element, value) {
+ element.checked = !!value;
+ },
+
+ style: function(element, value) {
+ element.style.cssText = value ? value : '';
+ }
+ }
+ };
+
+ Element._attributeTranslations.has = {};
+
+ $w('colSpan rowSpan vAlign dateTime accessKey tabIndex ' +
+ 'encType maxLength readOnly longDesc').each(function(attr) {
+ Element._attributeTranslations.write.names[attr.toLowerCase()] = attr;
+ Element._attributeTranslations.has[attr.toLowerCase()] = attr;
+ });
+
+ (function(v) {
+ Object.extend(v, {
+ href: v._getAttr,
+ src: v._getAttr,
+ type: v._getAttr,
+ action: v._getAttrNode,
+ disabled: v._flag,
+ checked: v._flag,
+ readonly: v._flag,
+ multiple: v._flag,
+ onload: v._getEv,
+ onunload: v._getEv,
+ onclick: v._getEv,
+ ondblclick: v._getEv,
+ onmousedown: v._getEv,
+ onmouseup: v._getEv,
+ onmouseover: v._getEv,
+ onmousemove: v._getEv,
+ onmouseout: v._getEv,
+ onfocus: v._getEv,
+ onblur: v._getEv,
+ onkeypress: v._getEv,
+ onkeydown: v._getEv,
+ onkeyup: v._getEv,
+ onsubmit: v._getEv,
+ onreset: v._getEv,
+ onselect: v._getEv,
+ onchange: v._getEv
+ });
+ })(Element._attributeTranslations.read.values);
+}
+
+else if (Prototype.Browser.Gecko && /rv:1\.8\.0/.test(navigator.userAgent)) {
+ Element.Methods.setOpacity = function(element, value) {
+ element = $(element);
+ element.style.opacity = (value == 1) ? 0.999999 :
+ (value === '') ? '' : (value < 0.00001) ? 0 : value;
+ return element;
+ };
+}
+
+else if (Prototype.Browser.WebKit) {
+ Element.Methods.setOpacity = function(element, value) {
+ element = $(element);
+ element.style.opacity = (value == 1 || value === '') ? '' :
+ (value < 0.00001) ? 0 : value;
+
+ if (value == 1)
+ if(element.tagName == 'IMG' && element.width) {
+ element.width++; element.width--;
+ } else try {
+ var n = document.createTextNode(' ');
+ element.appendChild(n);
+ element.removeChild(n);
+ } catch (e) { }
+
+ return element;
+ };
+
+ // Safari returns margins on body which is incorrect if the child is absolutely
+ // positioned. For performance reasons, redefine Element#cumulativeOffset for
+ // KHTML/WebKit only.
+ Element.Methods.cumulativeOffset = function(element) {
+ var valueT = 0, valueL = 0;
+ do {
+ valueT += element.offsetTop || 0;
+ valueL += element.offsetLeft || 0;
+ if (element.offsetParent == document.body)
+ if (Element.getStyle(element, 'position') == 'absolute') break;
+
+ element = element.offsetParent;
+ } while (element);
+
+ return Element._returnOffset(valueL, valueT);
+ };
+}
+
+if (Prototype.Browser.IE || Prototype.Browser.Opera) {
+ // IE and Opera are missing .innerHTML support for TABLE-related and SELECT elements
+ Element.Methods.update = function(element, content) {
+ element = $(element);
+
+ if (content && content.toElement) content = content.toElement();
+ if (Object.isElement(content)) return element.update().insert(content);
+
+ content = Object.toHTML(content);
+ var tagName = element.tagName.toUpperCase();
+
+ if (tagName in Element._insertionTranslations.tags) {
+ $A(element.childNodes).each(function(node) { element.removeChild(node) });
+ Element._getContentFromAnonymousElement(tagName, content.stripScripts())
+ .each(function(node) { element.appendChild(node) });
+ }
+ else element.innerHTML = content.stripScripts();
+
+ content.evalScripts.bind(content).defer();
+ return element;
+ };
+}
+
+if ('outerHTML' in document.createElement('div')) {
+ Element.Methods.replace = function(element, content) {
+ element = $(element);
+
+ if (content && content.toElement) content = content.toElement();
+ if (Object.isElement(content)) {
+ element.parentNode.replaceChild(content, element);
+ return element;
+ }
+
+ content = Object.toHTML(content);
+ var parent = element.parentNode, tagName = parent.tagName.toUpperCase();
+
+ if (Element._insertionTranslations.tags[tagName]) {
+ var nextSibling = element.next();
+ var fragments = Element._getContentFromAnonymousElement(tagName, content.stripScripts());
+ parent.removeChild(element);
+ if (nextSibling)
+ fragments.each(function(node) { parent.insertBefore(node, nextSibling) });
+ else
+ fragments.each(function(node) { parent.appendChild(node) });
+ }
+ else element.outerHTML = content.stripScripts();
+
+ content.evalScripts.bind(content).defer();
+ return element;
+ };
+}
+
+Element._returnOffset = function(l, t) {
+ var result = [l, t];
+ result.left = l;
+ result.top = t;
+ return result;
+};
+
+Element._getContentFromAnonymousElement = function(tagName, html) {
+ var div = new Element('div'), t = Element._insertionTranslations.tags[tagName];
+ if (t) {
+ div.innerHTML = t[0] + html + t[1];
+ t[2].times(function() { div = div.firstChild });
+ } else div.innerHTML = html;
+ return $A(div.childNodes);
+};
+
+Element._insertionTranslations = {
+ before: function(element, node) {
+ element.parentNode.insertBefore(node, element);
+ },
+ top: function(element, node) {
+ element.insertBefore(node, element.firstChild);
+ },
+ bottom: function(element, node) {
+ element.appendChild(node);
+ },
+ after: function(element, node) {
+ element.parentNode.insertBefore(node, element.nextSibling);
+ },
+ tags: {
+ TABLE: ['<table>', '</table>', 1],
+ TBODY: ['<table><tbody>', '</tbody></table>', 2],
+ TR: ['<table><tbody><tr>', '</tr></tbody></table>', 3],
+ TD: ['<table><tbody><tr><td>', '</td></tr></tbody></table>', 4],
+ SELECT: ['<select>', '</select>', 1]
+ }
+};
+
+(function() {
+ Object.extend(this.tags, {
+ THEAD: this.tags.TBODY,
+ TFOOT: this.tags.TBODY,
+ TH: this.tags.TD
+ });
+}).call(Element._insertionTranslations);
+
+Element.Methods.Simulated = {
+ hasAttribute: function(element, attribute) {
+ attribute = Element._attributeTranslations.has[attribute] || attribute;
+ var node = $(element).getAttributeNode(attribute);
+ return node && node.specified;
+ }
+};
+
+Element.Methods.ByTag = { };
+
+Object.extend(Element, Element.Methods);
+
+if (!Prototype.BrowserFeatures.ElementExtensions &&
+ document.createElement('div').__proto__) {
+ window.HTMLElement = { };
+ window.HTMLElement.prototype = document.createElement('div').__proto__;
+ Prototype.BrowserFeatures.ElementExtensions = true;
+}
+
+Element.extend = (function() {
+ if (Prototype.BrowserFeatures.SpecificElementExtensions)
+ return Prototype.K;
+
+ var Methods = { }, ByTag = Element.Methods.ByTag;
+
+ var extend = Object.extend(function(element) {
+ if (!element || element._extendedByPrototype ||
+ element.nodeType != 1 || element == window) return element;
+
+ var methods = Object.clone(Methods),
+ tagName = element.tagName, property, value;
+
+ // extend methods for specific tags
+ if (ByTag[tagName]) Object.extend(methods, ByTag[tagName]);
+
+ for (property in methods) {
+ value = methods[property];
+ if (Object.isFunction(value) && !(property in element))
+ element[property] = value.methodize();
+ }
+
+ element._extendedByPrototype = Prototype.emptyFunction;
+ return element;
+
+ }, {
+ refresh: function() {
+ // extend methods for all tags (Safari doesn't need this)
+ if (!Prototype.BrowserFeatures.ElementExtensions) {
+ Object.extend(Methods, Element.Methods);
+ Object.extend(Methods, Element.Methods.Simulated);
+ }
+ }
+ });
+
+ extend.refresh();
+ return extend;
+})();
+
+Element.hasAttribute = function(element, attribute) {
+ if (element.hasAttribute) return element.hasAttribute(attribute);
+ return Element.Methods.Simulated.hasAttribute(element, attribute);
+};
+
+Element.addMethods = function(methods) {
+ var F = Prototype.BrowserFeatures, T = Element.Methods.ByTag;
+
+ if (!methods) {
+ Object.extend(Form, Form.Methods);
+ Object.extend(Form.Element, Form.Element.Methods);
+ Object.extend(Element.Methods.ByTag, {
+ "FORM": Object.clone(Form.Methods),
+ "INPUT": Object.clone(Form.Element.Methods),
+ "SELECT": Object.clone(Form.Element.Methods),
+ "TEXTAREA": Object.clone(Form.Element.Methods)
+ });
+ }
+
+ if (arguments.length == 2) {
+ var tagName = methods;
+ methods = arguments[1];
+ }
+
+ if (!tagName) Object.extend(Element.Methods, methods || { });
+ else {
+ if (Object.isArray(tagName)) tagName.each(extend);
+ else extend(tagName);
+ }
+
+ function extend(tagName) {
+ tagName = tagName.toUpperCase();
+ if (!Element.Methods.ByTag[tagName])
+ Element.Methods.ByTag[tagName] = { };
+ Object.extend(Element.Methods.ByTag[tagName], methods);
+ }
+
+ function copy(methods, destination, onlyIfAbsent) {
+ onlyIfAbsent = onlyIfAbsent || false;
+ for (var property in methods) {
+ var value = methods[property];
+ if (!Object.isFunction(value)) continue;
+ if (!onlyIfAbsent || !(property in destination))
+ destination[property] = value.methodize();
+ }
+ }
+
+ function findDOMClass(tagName) {
+ var klass;
+ var trans = {
+ "OPTGROUP": "OptGroup", "TEXTAREA": "TextArea", "P": "Paragraph",
+ "FIELDSET": "FieldSet", "UL": "UList", "OL": "OList", "DL": "DList",
+ "DIR": "Directory", "H1": "Heading", "H2": "Heading", "H3": "Heading",
+ "H4": "Heading", "H5": "Heading", "H6": "Heading", "Q": "Quote",
+ "INS": "Mod", "DEL": "Mod", "A": "Anchor", "IMG": "Image", "CAPTION":
+ "TableCaption", "COL": "TableCol", "COLGROUP": "TableCol", "THEAD":
+ "TableSection", "TFOOT": "TableSection", "TBODY": "TableSection", "TR":
+ "TableRow", "TH": "TableCell", "TD": "TableCell", "FRAMESET":
+ "FrameSet", "IFRAME": "IFrame"
+ };
+ if (trans[tagName]) klass = 'HTML' + trans[tagName] + 'Element';
+ if (window[klass]) return window[klass];
+ klass = 'HTML' + tagName + 'Element';
+ if (window[klass]) return window[klass];
+ klass = 'HTML' + tagName.capitalize() + 'Element';
+ if (window[klass]) return window[klass];
+
+ window[klass] = { };
+ window[klass].prototype = document.createElement(tagName).__proto__;
+ return window[klass];
+ }
+
+ if (F.ElementExtensions) {
+ copy(Element.Methods, HTMLElement.prototype);
+ copy(Element.Methods.Simulated, HTMLElement.prototype, true);
+ }
+
+ if (F.SpecificElementExtensions) {
+ for (var tag in Element.Methods.ByTag) {
+ var klass = findDOMClass(tag);
+ if (Object.isUndefined(klass)) continue;
+ copy(T[tag], klass.prototype);
+ }
+ }
+
+ Object.extend(Element, Element.Methods);
+ delete Element.ByTag;
+
+ if (Element.extend.refresh) Element.extend.refresh();
+ Element.cache = { };
+};
+
+document.viewport = {
+ getDimensions: function() {
+ var dimensions = { };
+ var B = Prototype.Browser;
+ $w('width height').each(function(d) {
+ var D = d.capitalize();
+ dimensions[d] = (B.WebKit && !document.evaluate) ? self['inner' + D] :
+ (B.Opera) ? document.body['client' + D] : document.documentElement['client' + D];
+ });
+ return dimensions;
+ },
+
+ getWidth: function() {
+ return this.getDimensions().width;
+ },
+
+ getHeight: function() {
+ return this.getDimensions().height;
+ },
+
+ getScrollOffsets: function() {
+ return Element._returnOffset(
+ window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft,
+ window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop);
+ }
+};
+/* Portions of the Selector class are derived from Jack Slocum’s DomQuery,
+ * part of YUI-Ext version 0.40, distributed under the terms of an MIT-style
+ * license. Please see http://www.yui-ext.com/ for more information. */
+
+var Selector = Class.create({
+ initialize: function(expression) {
+ this.expression = expression.strip();
+ this.compileMatcher();
+ },
+
+ shouldUseXPath: function() {
+ if (!Prototype.BrowserFeatures.XPath) return false;
+
+ var e = this.expression;
+
+ // Safari 3 chokes on :*-of-type and :empty
+ if (Prototype.Browser.WebKit &&
+ (e.include("-of-type") || e.include(":empty")))
+ return false;
+
+ // XPath can't do namespaced attributes, nor can it read
+ // the "checked" property from DOM nodes
+ if ((/(\[[\w-]*?:|:checked)/).test(this.expression))
+ return false;
+
+ return true;
+ },
+
+ compileMatcher: function() {
+ if (this.shouldUseXPath())
+ return this.compileXPathMatcher();
+
+ var e = this.expression, ps = Selector.patterns, h = Selector.handlers,
+ c = Selector.criteria, le, p, m;
+
+ if (Selector._cache[e]) {
+ this.matcher = Selector._cache[e];
+ return;
+ }
+
+ this.matcher = ["this.matcher = function(root) {",
+ "var r = root, h = Selector.handlers, c = false, n;"];
+
+ while (e && le != e && (/\S/).test(e)) {
+ le = e;
+ for (var i in ps) {
+ p = ps[i];
+ if (m = e.match(p)) {
+ this.matcher.push(Object.isFunction(c[i]) ? c[i](m) :
+ new Template(c[i]).evaluate(m));
+ e = e.replace(m[0], '');
+ break;
+ }
+ }
+ }
+
+ this.matcher.push("return h.unique(n);\n}");
+ eval(this.matcher.join('\n'));
+ Selector._cache[this.expression] = this.matcher;
+ },
+
+ compileXPathMatcher: function() {
+ var e = this.expression, ps = Selector.patterns,
+ x = Selector.xpath, le, m;
+
+ if (Selector._cache[e]) {
+ this.xpath = Selector._cache[e]; return;
+ }
+
+ this.matcher = ['.//*'];
+ while (e && le != e && (/\S/).test(e)) {
+ le = e;
+ for (var i in ps) {
+ if (m = e.match(ps[i])) {
+ this.matcher.push(Object.isFunction(x[i]) ? x[i](m) :
+ new Template(x[i]).evaluate(m));
+ e = e.replace(m[0], '');
+ break;
+ }
+ }
+ }
+
+ this.xpath = this.matcher.join('');
+ Selector._cache[this.expression] = this.xpath;
+ },
+
+ findElements: function(root) {
+ root = root || document;
+ if (this.xpath) return document._getElementsByXPath(this.xpath, root);
+ return this.matcher(root);
+ },
+
+ match: function(element) {
+ this.tokens = [];
+
+ var e = this.expression, ps = Selector.patterns, as = Selector.assertions;
+ var le, p, m;
+
+ while (e && le !== e && (/\S/).test(e)) {
+ le = e;
+ for (var i in ps) {
+ p = ps[i];
+ if (m = e.match(p)) {
+ // use the Selector.assertions methods unless the selector
+ // is too complex.
+ if (as[i]) {
+ this.tokens.push([i, Object.clone(m)]);
+ e = e.replace(m[0], '');
+ } else {
+ // reluctantly do a document-wide search
+ // and look for a match in the array
+ return this.findElements(document).include(element);
+ }
+ }
+ }
+ }
+
+ var match = true, name, matches;
+ for (var i = 0, token; token = this.tokens[i]; i++) {
+ name = token[0], matches = token[1];
+ if (!Selector.assertions[name](element, matches)) {
+ match = false; break;
+ }
+ }
+
+ return match;
+ },
+
+ toString: function() {
+ return this.expression;
+ },
+
+ inspect: function() {
+ return "#<Selector:" + this.expression.inspect() + ">";
+ }
+});
+
+Object.extend(Selector, {
+ _cache: { },
+
+ xpath: {
+ descendant: "//*",
+ child: "/*",
+ adjacent: "/following-sibling::*[1]",
+ laterSibling: '/following-sibling::*',
+ tagName: function(m) {
+ if (m[1] == '*') return '';
+ return "[local-name()='" + m[1].toLowerCase() +
+ "' or local-name()='" + m[1].toUpperCase() + "']";
+ },
+ className: "[contains(concat(' ', @class, ' '), ' #{1} ')]",
+ id: "[@id='#{1}']",
+ attrPresence: function(m) {
+ m[1] = m[1].toLowerCase();
+ return new Template("[@#{1}]").evaluate(m);
+ },
+ attr: function(m) {
+ m[1] = m[1].toLowerCase();
+ m[3] = m[5] || m[6];
+ return new Template(Selector.xpath.operators[m[2]]).evaluate(m);
+ },
+ pseudo: function(m) {
+ var h = Selector.xpath.pseudos[m[1]];
+ if (!h) return '';
+ if (Object.isFunction(h)) return h(m);
+ return new Template(Selector.xpath.pseudos[m[1]]).evaluate(m);
+ },
+ operators: {
+ '=': "[@#{1}='#{3}']",
+ '!=': "[@#{1}!='#{3}']",
+ '^=': "[starts-with(@#{1}, '#{3}')]",
+ '$=': "[substring(@#{1}, (string-length(@#{1}) - string-length('#{3}') + 1))='#{3}']",
+ '*=': "[contains(@#{1}, '#{3}')]",
+ '~=': "[contains(concat(' ', @#{1}, ' '), ' #{3} ')]",
+ '|=': "[contains(concat('-', @#{1}, '-'), '-#{3}-')]"
+ },
+ pseudos: {
+ 'first-child': '[not(preceding-sibling::*)]',
+ 'last-child': '[not(following-sibling::*)]',
+ 'only-child': '[not(preceding-sibling::* or following-sibling::*)]',
+ 'empty': "[count(*) = 0 and (count(text()) = 0 or translate(text(), ' \t\r\n', '') = '')]",
+ 'checked': "[@checked]",
+ 'disabled': "[@disabled]",
+ 'enabled': "[not(@disabled)]",
+ 'not': function(m) {
+ var e = m[6], p = Selector.patterns,
+ x = Selector.xpath, le, v;
+
+ var exclusion = [];
+ while (e && le != e && (/\S/).test(e)) {
+ le = e;
+ for (var i in p) {
+ if (m = e.match(p[i])) {
+ v = Object.isFunction(x[i]) ? x[i](m) : new Template(x[i]).evaluate(m);
+ exclusion.push("(" + v.substring(1, v.length - 1) + ")");
+ e = e.replace(m[0], '');
+ break;
+ }
+ }
+ }
+ return "[not(" + exclusion.join(" and ") + ")]";
+ },
+ 'nth-child': function(m) {
+ return Selector.xpath.pseudos.nth("(count(./preceding-sibling::*) + 1) ", m);
+ },
+ 'nth-last-child': function(m) {
+ return Selector.xpath.pseudos.nth("(count(./following-sibling::*) + 1) ", m);
+ },
+ 'nth-of-type': function(m) {
+ return Selector.xpath.pseudos.nth("position() ", m);
+ },
+ 'nth-last-of-type': function(m) {
+ return Selector.xpath.pseudos.nth("(last() + 1 - position()) ", m);
+ },
+ 'first-of-type': function(m) {
+ m[6] = "1"; return Selector.xpath.pseudos['nth-of-type'](m);
+ },
+ 'last-of-type': function(m) {
+ m[6] = "1"; return Selector.xpath.pseudos['nth-last-of-type'](m);
+ },
+ 'only-of-type': function(m) {
+ var p = Selector.xpath.pseudos; return p['first-of-type'](m) + p['last-of-type'](m);
+ },
+ nth: function(fragment, m) {
+ var mm, formula = m[6], predicate;
+ if (formula == 'even') formula = '2n+0';
+ if (formula == 'odd') formula = '2n+1';
+ if (mm = formula.match(/^(\d+)$/)) // digit only
+ return '[' + fragment + "= " + mm[1] + ']';
+ if (mm = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b
+ if (mm[1] == "-") mm[1] = -1;
+ var a = mm[1] ? Number(mm[1]) : 1;
+ var b = mm[2] ? Number(mm[2]) : 0;
+ predicate = "[((#{fragment} - #{b}) mod #{a} = 0) and " +
+ "((#{fragment} - #{b}) div #{a} >= 0)]";
+ return new Template(predicate).evaluate({
+ fragment: fragment, a: a, b: b });
+ }
+ }
+ }
+ },
+
+ criteria: {
+ tagName: 'n = h.tagName(n, r, "#{1}", c); c = false;',
+ className: 'n = h.className(n, r, "#{1}", c); c = false;',
+ id: 'n = h.id(n, r, "#{1}", c); c = false;',
+ attrPresence: 'n = h.attrPresence(n, r, "#{1}", c); c = false;',
+ attr: function(m) {
+ m[3] = (m[5] || m[6]);
+ return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}", c); c = false;').evaluate(m);
+ },
+ pseudo: function(m) {
+ if (m[6]) m[6] = m[6].replace(/"/g, '\\"');
+ return new Template('n = h.pseudo(n, "#{1}", "#{6}", r, c); c = false;').evaluate(m);
+ },
+ descendant: 'c = "descendant";',
+ child: 'c = "child";',
+ adjacent: 'c = "adjacent";',
+ laterSibling: 'c = "laterSibling";'
+ },
+
+ patterns: {
+ // combinators must be listed first
+ // (and descendant needs to be last combinator)
+ laterSibling: /^\s*~\s*/,
+ child: /^\s*>\s*/,
+ adjacent: /^\s*\+\s*/,
+ descendant: /^\s/,
+
+ // selectors follow
+ tagName: /^\s*(\*|[\w\-]+)(\b|$)?/,
+ id: /^#([\w\-\*]+)(\b|$)/,
+ className: /^\.([\w\-\*]+)(\b|$)/,
+ pseudo:
+/^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|(?=\s|[:+~>]))/,
+ attrPresence: /^\[([\w]+)\]/,
+ attr: /\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\4]*?)\4|([^'"][^\]]*?)))?\]/
+ },
+
+ // for Selector.match and Element#match
+ assertions: {
+ tagName: function(element, matches) {
+ return matches[1].toUpperCase() == element.tagName.toUpperCase();
+ },
+
+ className: function(element, matches) {
+ return Element.hasClassName(element, matches[1]);
+ },
+
+ id: function(element, matches) {
+ return element.id === matches[1];
+ },
+
+ attrPresence: function(element, matches) {
+ return Element.hasAttribute(element, matches[1]);
+ },
+
+ attr: function(element, matches) {
+ var nodeValue = Element.readAttribute(element, matches[1]);
+ return nodeValue && Selector.operators[matches[2]](nodeValue, matches[5] || matches[6]);
+ }
+ },
+
+ handlers: {
+ // UTILITY FUNCTIONS
+ // joins two collections
+ concat: function(a, b) {
+ for (var i = 0, node; node = b[i]; i++)
+ a.push(node);
+ return a;
+ },
+
+ // marks an array of nodes for counting
+ mark: function(nodes) {
+ var _true = Prototype.emptyFunction;
+ for (var i = 0, node; node = nodes[i]; i++)
+ node._countedByPrototype = _true;
+ return nodes;
+ },
+
+ unmark: function(nodes) {
+ for (var i = 0, node; node = nodes[i]; i++)
+ node._countedByPrototype = undefined;
+ return nodes;
+ },
+
+ // mark each child node with its position (for nth calls)
+ // "ofType" flag indicates whether we're indexing for nth-of-type
+ // rather than nth-child
+ index: function(parentNode, reverse, ofType) {
+ parentNode._countedByPrototype = Prototype.emptyFunction;
+ if (reverse) {
+ for (var nodes = parentNode.childNodes, i = nodes.length - 1, j = 1; i >= 0; i--) {
+ var node = nodes[i];
+ if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++;
+ }
+ } else {
+ for (var i = 0, j = 1, nodes = parentNode.childNodes; node = nodes[i]; i++)
+ if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++;
+ }
+ },
+
+ // filters out duplicates and extends all nodes
+ unique: function(nodes) {
+ if (nodes.length == 0) return nodes;
+ var results = [], n;
+ for (var i = 0, l = nodes.length; i < l; i++)
+ if (!(n = nodes[i])._countedByPrototype) {
+ n._countedByPrototype = Prototype.emptyFunction;
+ results.push(Element.extend(n));
+ }
+ return Selector.handlers.unmark(results);
+ },
+
+ // COMBINATOR FUNCTIONS
+ descendant: function(nodes) {
+ var h = Selector.handlers;
+ for (var i = 0, results = [], node; node = nodes[i]; i++)
+ h.concat(results, node.getElementsByTagName('*'));
+ return results;
+ },
+
+ child: function(nodes) {
+ var h = Selector.handlers;
+ for (var i = 0, results = [], node; node = nodes[i]; i++) {
+ for (var j = 0, child; child = node.childNodes[j]; j++)
+ if (child.nodeType == 1 && child.tagName != '!') results.push(child);
+ }
+ return results;
+ },
+
+ adjacent: function(nodes) {
+ for (var i = 0, results = [], node; node = nodes[i]; i++) {
+ var next = this.nextElementSibling(node);
+ if (next) results.push(next);
+ }
+ return results;
+ },
+
+ laterSibling: function(nodes) {
+ var h = Selector.handlers;
+ for (var i = 0, results = [], node; node = nodes[i]; i++)
+ h.concat(results, Element.nextSiblings(node));
+ return results;
+ },
+
+ nextElementSibling: function(node) {
+ while (node = node.nextSibling)
+ if (node.nodeType == 1) return node;
+ return null;
+ },
+
+ previousElementSibling: function(node) {
+ while (node = node.previousSibling)
+ if (node.nodeType == 1) return node;
+ return null;
+ },
+
+ // TOKEN FUNCTIONS
+ tagName: function(nodes, root, tagName, combinator) {
+ var uTagName = tagName.toUpperCase();
+ var results = [], h = Selector.handlers;
+ if (nodes) {
+ if (combinator) {
+ // fastlane for ordinary descendant combinators
+ if (combinator == "descendant") {
+ for (var i = 0, node; node = nodes[i]; i++)
+ h.concat(results, node.getElementsByTagName(tagName));
+ return results;
+ } else nodes = this[combinator](nodes);
+ if (tagName == "*") return nodes;
+ }
+ for (var i = 0, node; node = nodes[i]; i++)
+ if (node.tagName.toUpperCase() === uTagName) results.push(node);
+ return results;
+ } else return root.getElementsByTagName(tagName);
+ },
+
+ id: function(nodes, root, id, combinator) {
+ var targetNode = $(id), h = Selector.handlers;
+ if (!targetNode) return [];
+ if (!nodes && root == document) return [targetNode];
+ if (nodes) {
+ if (combinator) {
+ if (combinator == 'child') {
+ for (var i = 0, node; node = nodes[i]; i++)
+ if (targetNode.parentNode == node) return [targetNode];
+ } else if (combinator == 'descendant') {
+ for (var i = 0, node; node = nodes[i]; i++)
+ if (Element.descendantOf(targetNode, node)) return [targetNode];
+ } else if (combinator == 'adjacent') {
+ for (var i = 0, node; node = nodes[i]; i++)
+ if (Selector.handlers.previousElementSibling(targetNode) == node)
+ return [targetNode];
+ } else nodes = h[combinator](nodes);
+ }
+ for (var i = 0, node; node = nodes[i]; i++)
+ if (node == targetNode) return [targetNode];
+ return [];
+ }
+ return (targetNode && Element.descendantOf(targetNode, root)) ? [targetNode] : [];
+ },
+
+ className: function(nodes, root, className, combinator) {
+ if (nodes && combinator) nodes = this[combinator](nodes);
+ return Selector.handlers.byClassName(nodes, root, className);
+ },
+
+ byClassName: function(nodes, root, className) {
+ if (!nodes) nodes = Selector.handlers.descendant([root]);
+ var needle = ' ' + className + ' ';
+ for (var i = 0, results = [], node, nodeClassName; node = nodes[i]; i++) {
+ nodeClassName = node.className;
+ if (nodeClassName.length == 0) continue;
+ if (nodeClassName == className || (' ' + nodeClassName + ' ').include(needle))
+ results.push(node);
+ }
+ return results;
+ },
+
+ attrPresence: function(nodes, root, attr, combinator) {
+ if (!nodes) nodes = root.getElementsByTagName("*");
+ if (nodes && combinator) nodes = this[combinator](nodes);
+ var results = [];
+ for (var i = 0, node; node = nodes[i]; i++)
+ if (Element.hasAttribute(node, attr)) results.push(node);
+ return results;
+ },
+
+ attr: function(nodes, root, attr, value, operator, combinator) {
+ if (!nodes) nodes = root.getElementsByTagName("*");
+ if (nodes && combinator) nodes = this[combinator](nodes);
+ var handler = Selector.operators[operator], results = [];
+ for (var i = 0, node; node = nodes[i]; i++) {
+ var nodeValue = Element.readAttribute(node, attr);
+ if (nodeValue === null) continue;
+ if (handler(nodeValue, value)) results.push(node);
+ }
+ return results;
+ },
+
+ pseudo: function(nodes, name, value, root, combinator) {
+ if (nodes && combinator) nodes = this[combinator](nodes);
+ if (!nodes) nodes = root.getElementsByTagName("*");
+ return Selector.pseudos[name](nodes, value, root);
+ }
+ },
+
+ pseudos: {
+ 'first-child': function(nodes, value, root) {
+ for (var i = 0, results = [], node; node = nodes[i]; i++) {
+ if (Selector.handlers.previousElementSibling(node)) continue;
+ results.push(node);
+ }
+ return results;
+ },
+ 'last-child': function(nodes, value, root) {
+ for (var i = 0, results = [], node; node = nodes[i]; i++) {
+ if (Selector.handlers.nextElementSibling(node)) continue;
+ results.push(node);
+ }
+ return results;
+ },
+ 'only-child': function(nodes, value, root) {
+ var h = Selector.handlers;
+ for (var i = 0, results = [], node; node = nodes[i]; i++)
+ if (!h.previousElementSibling(node) && !h.nextElementSibling(node))
+ results.push(node);
+ return results;
+ },
+ 'nth-child': function(nodes, formula, root) {
+ return Selector.pseudos.nth(nodes, formula, root);
+ },
+ 'nth-last-child': function(nodes, formula, root) {
+ return Selector.pseudos.nth(nodes, formula, root, true);
+ },
+ 'nth-of-type': function(nodes, formula, root) {
+ return Selector.pseudos.nth(nodes, formula, root, false, true);
+ },
+ 'nth-last-of-type': function(nodes, formula, root) {
+ return Selector.pseudos.nth(nodes, formula, root, true, true);
+ },
+ 'first-of-type': function(nodes, formula, root) {
+ return Selector.pseudos.nth(nodes, "1", root, false, true);
+ },
+ 'last-of-type': function(nodes, formula, root) {
+ return Selector.pseudos.nth(nodes, "1", root, true, true);
+ },
+ 'only-of-type': function(nodes, formula, root) {
+ var p = Selector.pseudos;
+ return p['last-of-type'](p['first-of-type'](nodes, formula, root), formula, root);
+ },
+
+ // handles the an+b logic
+ getIndices: function(a, b, total) {
+ if (a == 0) return b > 0 ? [b] : [];
+ return $R(1, total).inject([], function(memo, i) {
+ if (0 == (i - b) % a && (i - b) / a >= 0) memo.push(i);
+ return memo;
+ });
+ },
+
+ // handles nth(-last)-child, nth(-last)-of-type, and (first|last)-of-type
+ nth: function(nodes, formula, root, reverse, ofType) {
+ if (nodes.length == 0) return [];
+ if (formula == 'even') formula = '2n+0';
+ if (formula == 'odd') formula = '2n+1';
+ var h = Selector.handlers, results = [], indexed = [], m;
+ h.mark(nodes);
+ for (var i = 0, node; node = nodes[i]; i++) {
+ if (!node.parentNode._countedByPrototype) {
+ h.index(node.parentNode, reverse, ofType);
+ indexed.push(node.parentNode);
+ }
+ }
+ if (formula.match(/^\d+$/)) { // just a number
+ formula = Number(formula);
+ for (var i = 0, node; node = nodes[i]; i++)
+ if (node.nodeIndex == formula) results.push(node);
+ } else if (m = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b
+ if (m[1] == "-") m[1] = -1;
+ var a = m[1] ? Number(m[1]) : 1;
+ var b = m[2] ? Number(m[2]) : 0;
+ var indices = Selector.pseudos.getIndices(a, b, nodes.length);
+ for (var i = 0, node, l = indices.length; node = nodes[i]; i++) {
+ for (var j = 0; j < l; j++)
+ if (node.nodeIndex == indices[j]) results.push(node);
+ }
+ }
+ h.unmark(nodes);
+ h.unmark(indexed);
+ return results;
+ },
+
+ 'empty': function(nodes, value, root) {
+ for (var i = 0, results = [], node; node = nodes[i]; i++) {
+ // IE treats comments as element nodes
+ if (node.tagName == '!' || (node.firstChild && !node.innerHTML.match(/^\s*$/))) continue;
+ results.push(node);
+ }
+ return results;
+ },
+
+ 'not': function(nodes, selector, root) {
+ var h = Selector.handlers, selectorType, m;
+ var exclusions = new Selector(selector).findElements(root);
+ h.mark(exclusions);
+ for (var i = 0, results = [], node; node = nodes[i]; i++)
+ if (!node._countedByPrototype) results.push(node);
+ h.unmark(exclusions);
+ return results;
+ },
+
+ 'enabled': function(nodes, value, root) {
+ for (var i = 0, results = [], node; node = nodes[i]; i++)
+ if (!node.disabled) results.push(node);
+ return results;
+ },
+
+ 'disabled': function(nodes, value, root) {
+ for (var i = 0, results = [], node; node = nodes[i]; i++)
+ if (node.disabled) results.push(node);
+ return results;
+ },
+
+ 'checked': function(nodes, value, root) {
+ for (var i = 0, results = [], node; node = nodes[i]; i++)
+ if (node.checked) results.push(node);
+ return results;
+ }
+ },
+
+ operators: {
+ '=': function(nv, v) { return nv == v; },
+ '!=': function(nv, v) { return nv != v; },
+ '^=': function(nv, v) { return nv.startsWith(v); },
+ '$=': function(nv, v) { return nv.endsWith(v); },
+ '*=': function(nv, v) { return nv.include(v); },
+ '~=': function(nv, v) { return (' ' + nv + ' ').include(' ' + v + ' '); },
+ '|=': function(nv, v) { return ('-' + nv.toUpperCase() + '-').include('-' + v.toUpperCase() + '-'); }
+ },
+
+ split: function(expression) {
+ var expressions = [];
+ expression.scan(/(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/, function(m) {
+ expressions.push(m[1].strip());
+ });
+ return expressions;
+ },
+
+ matchElements: function(elements, expression) {
+ var matches = $$(expression), h = Selector.handlers;
+ h.mark(matches);
+ for (var i = 0, results = [], element; element = elements[i]; i++)
+ if (element._countedByPrototype) results.push(element);
+ h.unmark(matches);
+ return results;
+ },
+
+ findElement: function(elements, expression, index) {
+ if (Object.isNumber(expression)) {
+ index = expression; expression = false;
+ }
+ return Selector.matchElements(elements, expression || '*')[index || 0];
+ },
+
+ findChildElements: function(element, expressions) {
+ expressions = Selector.split(expressions.join(','));
+ var results = [], h = Selector.handlers;
+ for (var i = 0, l = expressions.length, selector; i < l; i++) {
+ selector = new Selector(expressions[i].strip());
+ h.concat(results, selector.findElements(element));
+ }
+ return (l > 1) ? h.unique(results) : results;
+ }
+});
+
+if (Prototype.Browser.IE) {
+ Object.extend(Selector.handlers, {
+ // IE returns comment nodes on getElementsByTagName("*").
+ // Filter them out.
+ concat: function(a, b) {
+ for (var i = 0, node; node = b[i]; i++)
+ if (node.tagName !== "!") a.push(node);
+ return a;
+ },
+
+ // IE improperly serializes _countedByPrototype in (inner|outer)HTML.
+ unmark: function(nodes) {
+ for (var i = 0, node; node = nodes[i]; i++)
+ node.removeAttribute('_countedByPrototype');
+ return nodes;
+ }
+ });
+}
+
+function $$() {
+ return Selector.findChildElements(document, $A(arguments));
+}
+var Form = {
+ reset: function(form) {
+ $(form).reset();
+ return form;
+ },
+
+ serializeElements: function(elements, options) {
+ if (typeof options != 'object') options = { hash: !!options };
+ else if (Object.isUndefined(options.hash)) options.hash = true;
+ var key, value, submitted = false, submit = options.submit;
+
+ var data = elements.inject({ }, function(result, element) {
+ if (!element.disabled && element.name) {
+ key = element.name; value = $(element).getValue();
+ if (value != null && (element.type != 'submit' || (!submitted &&
+ submit !== false && (!submit || key == submit) && (submitted = true)))) {
+ if (key in result) {
+ // a key is already present; construct an array of values
+ if (!Object.isArray(result[key])) result[key] = [result[key]];
+ result[key].push(value);
+ }
+ else result[key] = value;
+ }
+ }
+ return result;
+ });
+
+ return options.hash ? data : Object.toQueryString(data);
+ }
+};
+
+Form.Methods = {
+ serialize: function(form, options) {
+ return Form.serializeElements(Form.getElements(form), options);
+ },
+
+ getElements: function(form) {
+ return $A($(form).getElementsByTagName('*')).inject([],
+ function(elements, child) {
+ if (Form.Element.Serializers[child.tagName.toLowerCase()])
+ elements.push(Element.extend(child));
+ return elements;
+ }
+ );
+ },
+
+ getInputs: function(form, typeName, name) {
+ form = $(form);
+ var inputs = form.getElementsByTagName('input');
+
+ if (!typeName && !name) return $A(inputs).map(Element.extend);
+
+ for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) {
+ var input = inputs[i];
+ if ((typeName && input.type != typeName) || (name && input.name != name))
+ continue;
+ matchingInputs.push(Element.extend(input));
+ }
+
+ return matchingInputs;
+ },
+
+ disable: function(form) {
+ form = $(form);
+ Form.getElements(form).invoke('disable');
+ return form;
+ },
+
+ enable: function(form) {
+ form = $(form);
+ Form.getElements(form).invoke('enable');
+ return form;
+ },
+
+ findFirstElement: function(form) {
+ var elements = $(form).getElements().findAll(function(element) {
+ return 'hidden' != element.type && !element.disabled;
+ });
+ var firstByIndex = elements.findAll(function(element) {
+ return element.hasAttribute('tabIndex') && element.tabIndex >= 0;
+ }).sortBy(function(element) { return element.tabIndex }).first();
+
+ return firstByIndex ? firstByIndex : elements.find(function(element) {
+ return ['input', 'select', 'textarea'].include(element.tagName.toLowerCase());
+ });
+ },
+
+ focusFirstElement: function(form) {
+ form = $(form);
+ form.findFirstElement().activate();
+ return form;
+ },
+
+ request: function(form, options) {
+ form = $(form), options = Object.clone(options || { });
+
+ var params = options.parameters, action = form.readAttribute('action') || '';
+ if (action.blank()) action = window.location.href;
+ options.parameters = form.serialize(true);
+
+ if (params) {
+ if (Object.isString(params)) params = params.toQueryParams();
+ Object.extend(options.parameters, params);
+ }
+
+ if (form.hasAttribute('method') && !options.method)
+ options.method = form.method;
+
+ return new Ajax.Request(action, options);
+ }
+};
+
+/*--------------------------------------------------------------------------*/
+
+Form.Element = {
+ focus: function(element) {
+ $(element).focus();
+ return element;
+ },
+
+ select: function(element) {
+ $(element).select();
+ return element;
+ }
+};
+
+Form.Element.Methods = {
+ serialize: function(element) {
+ element = $(element);
+ if (!element.disabled && element.name) {
+ var value = element.getValue();
+ if (value != undefined) {
+ var pair = { };
+ pair[element.name] = value;
+ return Object.toQueryString(pair);
+ }
+ }
+ return '';
+ },
+
+ getValue: function(element) {
+ element = $(element);
+ var method = element.tagName.toLowerCase();
+ return Form.Element.Serializers[method](element);
+ },
+
+ setValue: function(element, value) {
+ element = $(element);
+ var method = element.tagName.toLowerCase();
+ Form.Element.Serializers[method](element, value);
+ return element;
+ },
+
+ clear: function(element) {
+ $(element).value = '';
+ return element;
+ },
+
+ present: function(element) {
+ return $(element).value != '';
+ },
+
+ activate: function(element) {
+ element = $(element);
+ try {
+ element.focus();
+ if (element.select && (element.tagName.toLowerCase() != 'input' ||
+ !['button', 'reset', 'submit'].include(element.type)))
+ element.select();
+ } catch (e) { }
+ return element;
+ },
+
+ disable: function(element) {
+ element = $(element);
+ element.blur();
+ element.disabled = true;
+ return element;
+ },
+
+ enable: function(element) {
+ element = $(element);
+ element.disabled = false;
+ return element;
+ }
+};
+
+/*--------------------------------------------------------------------------*/
+
+var Field = Form.Element;
+var $F = Form.Element.Methods.getValue;
+
+/*--------------------------------------------------------------------------*/
+
+Form.Element.Serializers = {
+ input: function(element, value) {
+ switch (element.type.toLowerCase()) {
+ case 'checkbox':
+ case 'radio':
+ return Form.Element.Serializers.inputSelector(element, value);
+ default:
+ return Form.Element.Serializers.textarea(element, value);
+ }
+ },
+
+ inputSelector: function(element, value) {
+ if (Object.isUndefined(value)) return element.checked ? element.value : null;
+ else element.checked = !!value;
+ },
+
+ textarea: function(element, value) {
+ if (Object.isUndefined(value)) return element.value;
+ else element.value = value;
+ },
+
+ select: function(element, index) {
+ if (Object.isUndefined(index))
+ return this[element.type == 'select-one' ?
+ 'selectOne' : 'selectMany'](element);
+ else {
+ var opt, value, single = !Object.isArray(index);
+ for (var i = 0, length = element.length; i < length; i++) {
+ opt = element.options[i];
+ value = this.optionValue(opt);
+ if (single) {
+ if (value == index) {
+ opt.selected = true;
+ return;
+ }
+ }
+ else opt.selected = index.include(value);
+ }
+ }
+ },
+
+ selectOne: function(element) {
+ var index = element.selectedIndex;
+ return index >= 0 ? this.optionValue(element.options[index]) : null;
+ },
+
+ selectMany: function(element) {
+ var values, length = element.length;
+ if (!length) return null;
+
+ for (var i = 0, values = []; i < length; i++) {
+ var opt = element.options[i];
+ if (opt.selected) values.push(this.optionValue(opt));
+ }
+ return values;
+ },
+
+ optionValue: function(opt) {
+ // extend element because hasAttribute may not be native
+ return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text;
+ }
+};
+
+/*--------------------------------------------------------------------------*/
+
+Abstract.TimedObserver = Class.create(PeriodicalExecuter, {
+ initialize: function($super, element, frequency, callback) {
+ $super(callback, frequency);
+ this.element = $(element);
+ this.lastValue = this.getValue();
+ },
+
+ execute: function() {
+ var value = this.getValue();
+ if (Object.isString(this.lastValue) && Object.isString(value) ?
+ this.lastValue != value : String(this.lastValue) != String(value)) {
+ this.callback(this.element, value);
+ this.lastValue = value;
+ }
+ }
+});
+
+Form.Element.Observer = Class.create(Abstract.TimedObserver, {
+ getValue: function() {
+ return Form.Element.getValue(this.element);
+ }
+});
+
+Form.Observer = Class.create(Abstract.TimedObserver, {
+ getValue: function() {
+ return Form.serialize(this.element);
+ }
+});
+
+/*--------------------------------------------------------------------------*/
+
+Abstract.EventObserver = Class.create({
+ initialize: function(element, callback) {
+ this.element = $(element);
+ this.callback = callback;
+
+ this.lastValue = this.getValue();
+ if (this.element.tagName.toLowerCase() == 'form')
+ this.registerFormCallbacks();
+ else
+ this.registerCallback(this.element);
+ },
+
+ onElementEvent: function() {
+ var value = this.getValue();
+ if (this.lastValue != value) {
+ this.callback(this.element, value);
+ this.lastValue = value;
+ }
+ },
+
+ registerFormCallbacks: function() {
+ Form.getElements(this.element).each(this.registerCallback, this);
+ },
+
+ registerCallback: function(element) {
+ if (element.type) {
+ switch (element.type.toLowerCase()) {
+ case 'checkbox':
+ case 'radio':
+ Event.observe(element, 'click', this.onElementEvent.bind(this));
+ break;
+ default:
+ Event.observe(element, 'change', this.onElementEvent.bind(this));
+ break;
+ }
+ }
+ }
+});
+
+Form.Element.EventObserver = Class.create(Abstract.EventObserver, {
+ getValue: function() {
+ return Form.Element.getValue(this.element);
+ }
+});
+
+Form.EventObserver = Class.create(Abstract.EventObserver, {
+ getValue: function() {
+ return Form.serialize(this.element);
+ }
+});
+if (!window.Event) var Event = { };
+
+Object.extend(Event, {
+ KEY_BACKSPACE: 8,
+ KEY_TAB: 9,
+ KEY_RETURN: 13,
+ KEY_ESC: 27,
+ KEY_LEFT: 37,
+ KEY_UP: 38,
+ KEY_RIGHT: 39,
+ KEY_DOWN: 40,
+ KEY_DELETE: 46,
+ KEY_HOME: 36,
+ KEY_END: 35,
+ KEY_PAGEUP: 33,
+ KEY_PAGEDOWN: 34,
+ KEY_INSERT: 45,
+
+ cache: { },
+
+ relatedTarget: function(event) {
+ var element;
+ switch(event.type) {
+ case 'mouseover': element = event.fromElement; break;
+ case 'mouseout': element = event.toElement; break;
+ default: return null;
+ }
+ return Element.extend(element);
+ }
+});
+
+Event.Methods = (function() {
+ var isButton;
+
+ if (Prototype.Browser.IE) {
+ var buttonMap = { 0: 1, 1: 4, 2: 2 };
+ isButton = function(event, code) {
+ return event.button == buttonMap[code];
+ };
+
+ } else if (Prototype.Browser.WebKit) {
+ isButton = function(event, code) {
+ switch (code) {
+ case 0: return event.which == 1 && !event.metaKey;
+ case 1: return event.which == 1 && event.metaKey;
+ default: return false;
+ }
+ };
+
+ } else {
+ isButton = function(event, code) {
+ return event.which ? (event.which === code + 1) : (event.button === code);
+ };
+ }
+
+ return {
+ isLeftClick: function(event) { return isButton(event, 0) },
+ isMiddleClick: function(event) { return isButton(event, 1) },
+ isRightClick: function(event) { return isButton(event, 2) },
+
+ element: function(event) {
+ var node = Event.extend(event).target;
+ return Element.extend(node.nodeType == Node.TEXT_NODE ? node.parentNode : node);
+ },
+
+ findElement: function(event, expression) {
+ var element = Event.element(event);
+ if (!expression) return element;
+ var elements = [element].concat(element.ancestors());
+ return Selector.findElement(elements, expression, 0);
+ },
+
+ pointer: function(event) {
+ return {
+ x: event.pageX || (event.clientX +
+ (document.documentElement.scrollLeft || document.body.scrollLeft)),
+ y: event.pageY || (event.clientY +
+ (document.documentElement.scrollTop || document.body.scrollTop))
+ };
+ },
+
+ pointerX: function(event) { return Event.pointer(event).x },
+ pointerY: function(event) { return Event.pointer(event).y },
+
+ stop: function(event) {
+ Event.extend(event);
+ event.preventDefault();
+ event.stopPropagation();
+ event.stopped = true;
+ }
+ };
+})();
+
+Event.extend = (function() {
+ var methods = Object.keys(Event.Methods).inject({ }, function(m, name) {
+ m[name] = Event.Methods[name].methodize();
+ return m;
+ });
+
+ if (Prototype.Browser.IE) {
+ Object.extend(methods, {
+ stopPropagation: function() { this.cancelBubble = true },
+ preventDefault: function() { this.returnValue = false },
+ inspect: function() { return "[object Event]" }
+ });
+
+ return function(event) {
+ if (!event) return false;
+ if (event._extendedByPrototype) return event;
+
+ event._extendedByPrototype = Prototype.emptyFunction;
+ var pointer = Event.pointer(event);
+ Object.extend(event, {
+ target: event.srcElement,
+ relatedTarget: Event.relatedTarget(event),
+ pageX: pointer.x,
+ pageY: pointer.y
+ });
+ return Object.extend(event, methods);
+ };
+
+ } else {
+ Event.prototype = Event.prototype || document.createEvent("HTMLEvents").__proto__;
+ Object.extend(Event.prototype, methods);
+ return Prototype.K;
+ }
+})();
+
+Object.extend(Event, (function() {
+ var cache = Event.cache;
+
+ function getEventID(element) {
+ if (element._prototypeEventID) return element._prototypeEventID[0];
+ arguments.callee.id = arguments.callee.id || 1;
+ return element._prototypeEventID = [++arguments.callee.id];
+ }
+
+ function getDOMEventName(eventName) {
+ if (eventName && eventName.include(':')) return "dataavailable";
+ return eventName;
+ }
+
+ function getCacheForID(id) {
+ return cache[id] = cache[id] || { };
+ }
+
+ function getWrappersForEventName(id, eventName) {
+ var c = getCacheForID(id);
+ return c[eventName] = c[eventName] || [];
+ }
+
+ function createWrapper(element, eventName, handler) {
+ var id = getEventID(element);
+ var c = getWrappersForEventName(id, eventName);
+ if (c.pluck("handler").include(handler)) return false;
+
+ var wrapper = function(event) {
+ if (!Event || !Event.extend ||
+ (event.eventName && event.eventName != eventName))
+ return false;
+
+ Event.extend(event);
+ handler.call(element, event);
+ };
+
+ wrapper.handler = handler;
+ c.push(wrapper);
+ return wrapper;
+ }
+
+ function findWrapper(id, eventName, handler) {
+ var c = getWrappersForEventName(id, eventName);
+ return c.find(function(wrapper) { return wrapper.handler == handler });
+ }
+
+ function destroyWrapper(id, eventName, handler) {
+ var c = getCacheForID(id);
+ if (!c[eventName]) return false;
+ c[eventName] = c[eventName].without(findWrapper(id, eventName, handler));
+ }
+
+ function destroyCache() {
+ for (var id in cache)
+ for (var eventName in cache[id])
+ cache[id][eventName] = null;
+ }
+
+ if (window.attachEvent) {
+ window.attachEvent("onunload", destroyCache);
+ }
+
+ return {
+ observe: function(element, eventName, handler) {
+ element = $(element);
+ var name = getDOMEventName(eventName);
+
+ var wrapper = createWrapper(element, eventName, handler);
+ if (!wrapper) return element;
+
+ if (element.addEventListener) {
+ element.addEventListener(name, wrapper, false);
+ } else {
+ element.attachEvent("on" + name, wrapper);
+ }
+
+ return element;
+ },
+
+ stopObserving: function(element, eventName, handler) {
+ element = $(element);
+ var id = getEventID(element), name = getDOMEventName(eventName);
+
+ if (!handler && eventName) {
+ getWrappersForEventName(id, eventName).each(function(wrapper) {
+ element.stopObserving(eventName, wrapper.handler);
+ });
+ return element;
+
+ } else if (!eventName) {
+ Object.keys(getCacheForID(id)).each(function(eventName) {
+ element.stopObserving(eventName);
+ });
+ return element;
+ }
+
+ var wrapper = findWrapper(id, eventName, handler);
+ if (!wrapper) return element;
+
+ if (element.removeEventListener) {
+ element.removeEventListener(name, wrapper, false);
+ } else {
+ element.detachEvent("on" + name, wrapper);
+ }
+
+ destroyWrapper(id, eventName, handler);
+
+ return element;
+ },
+
+ fire: function(element, eventName, memo) {
+ element = $(element);
+ if (element == document && document.createEvent && !element.dispatchEvent)
+ element = document.documentElement;
+
+ var event;
+ if (document.createEvent) {
+ event = document.createEvent("HTMLEvents");
+ event.initEvent("dataavailable", true, true);
+ } else {
+ event = document.createEventObject();
+ event.eventType = "ondataavailable";
+ }
+
+ event.eventName = eventName;
+ event.memo = memo || { };
+
+ if (document.createEvent) {
+ element.dispatchEvent(event);
+ } else {
+ element.fireEvent(event.eventType, event);
+ }
+
+ return Event.extend(event);
+ }
+ };
+})());
+
+Object.extend(Event, Event.Methods);
+
+Element.addMethods({
+ fire: Event.fire,
+ observe: Event.observe,
+ stopObserving: Event.stopObserving
+});
+
+Object.extend(document, {
+ fire: Element.Methods.fire.methodize(),
+ observe: Element.Methods.observe.methodize(),
+ stopObserving: Element.Methods.stopObserving.methodize(),
+ loaded: false
+});
+
+(function() {
+ /* Support for the DOMContentLoaded event is based on work by Dan Webb,
+ Matthias Miller, Dean Edwards and John Resig. */
+
+ var timer;
+
+ function fireContentLoadedEvent() {
+ if (document.loaded) return;
+ if (timer) window.clearInterval(timer);
+ document.fire("dom:loaded");
+ document.loaded = true;
+ }
+
+ if (document.addEventListener) {
+ if (Prototype.Browser.WebKit) {
+ timer = window.setInterval(function() {
+ if (/loaded|complete/.test(document.readyState))
+ fireContentLoadedEvent();
+ }, 0);
+
+ Event.observe(window, "load", fireContentLoadedEvent);
+
+ } else {
+ document.addEventListener("DOMContentLoaded",
+ fireContentLoadedEvent, false);
+ }
+
+ } else {
+ document.write("<script id=__onDOMContentLoaded defer src=//:><\/script>");
+ $("__onDOMContentLoaded").onreadystatechange = function() {
+ if (this.readyState == "complete") {
+ this.onreadystatechange = null;
+ fireContentLoadedEvent();
+ }
+ };
+ }
+})();
+/*------------------------------- DEPRECATED -------------------------------*/
+
+Hash.toQueryString = Object.toQueryString;
+
+var Toggle = { display: Element.toggle };
+
+Element.Methods.childOf = Element.Methods.descendantOf;
+
+var Insertion = {
+ Before: function(element, content) {
+ return Element.insert(element, {before:content});
+ },
+
+ Top: function(element, content) {
+ return Element.insert(element, {top:content});
+ },
+
+ Bottom: function(element, content) {
+ return Element.insert(element, {bottom:content});
+ },
+
+ After: function(element, content) {
+ return Element.insert(element, {after:content});
+ }
+};
+
+var $continue = new Error('"throw $continue" is deprecated, use "return" instead');
+
+// This should be moved to script.aculo.us; notice the deprecated methods
+// further below, that map to the newer Element methods.
+var Position = {
+ // set to true if needed, warning: firefox performance problems
+ // NOT neeeded for page scrolling, only if draggable contained in
+ // scrollable elements
+ includeScrollOffsets: false,
+
+ // must be called before calling withinIncludingScrolloffset, every time the
+ // page is scrolled
+ prepare: function() {
+ this.deltaX = window.pageXOffset
+ || document.documentElement.scrollLeft
+ || document.body.scrollLeft
+ || 0;
+ this.deltaY = window.pageYOffset
+ || document.documentElement.scrollTop
+ || document.body.scrollTop
+ || 0;
+ },
+
+ // caches x/y coordinate pair to use with overlap
+ within: function(element, x, y) {
+ if (this.includeScrollOffsets)
+ return this.withinIncludingScrolloffsets(element, x, y);
+ this.xcomp = x;
+ this.ycomp = y;
+ this.offset = Element.cumulativeOffset(element);
+
+ return (y >= this.offset[1] &&
+ y < this.offset[1] + element.offsetHeight &&
+ x >= this.offset[0] &&
+ x < this.offset[0] + element.offsetWidth);
+ },
+
+ withinIncludingScrolloffsets: function(element, x, y) {
+ var offsetcache = Element.cumulativeScrollOffset(element);
+
+ this.xcomp = x + offsetcache[0] - this.deltaX;
+ this.ycomp = y + offsetcache[1] - this.deltaY;
+ this.offset = Element.cumulativeOffset(element);
+
+ return (this.ycomp >= this.offset[1] &&
+ this.ycomp < this.offset[1] + element.offsetHeight &&
+ this.xcomp >= this.offset[0] &&
+ this.xcomp < this.offset[0] + element.offsetWidth);
+ },
+
+ // within must be called directly before
+ overlap: function(mode, element) {
+ if (!mode) return 0;
+ if (mode == 'vertical')
+ return ((this.offset[1] + element.offsetHeight) - this.ycomp) /
+ element.offsetHeight;
+ if (mode == 'horizontal')
+ return ((this.offset[0] + element.offsetWidth) - this.xcomp) /
+ element.offsetWidth;
+ },
+
+ // Deprecation layer -- use newer Element methods now (1.5.2).
+
+ cumulativeOffset: Element.Methods.cumulativeOffset,
+
+ positionedOffset: Element.Methods.positionedOffset,
+
+ absolutize: function(element) {
+ Position.prepare();
+ return Element.absolutize(element);
+ },
+
+ relativize: function(element) {
+ Position.prepare();
+ return Element.relativize(element);
+ },
+
+ realOffset: Element.Methods.cumulativeScrollOffset,
+
+ offsetParent: Element.Methods.getOffsetParent,
+
+ page: Element.Methods.viewportOffset,
+
+ clone: function(source, target, options) {
+ options = options || { };
+ return Element.clonePosition(target, source, options);
+ }
+};
+
+/*--------------------------------------------------------------------------*/
+
+if (!document.getElementsByClassName) document.getElementsByClassName = function(instanceMethods){
+ function iter(name) {
+ return name.blank() ? null : "[contains(concat(' ', @class, ' '), ' " + name + " ')]";
+ }
+
+ instanceMethods.getElementsByClassName = Prototype.BrowserFeatures.XPath ?
+ function(element, className) {
+ className = className.toString().strip();
+ var cond = /\s/.test(className) ? $w(className).map(iter).join('') : iter(className);
+ return cond ? document._getElementsByXPath('.//*' + cond, element) : [];
+ } : function(element, className) {
+ className = className.toString().strip();
+ var elements = [], classNames = (/\s/.test(className) ? $w(className) : null);
+ if (!classNames && !className) return elements;
+
+ var nodes = $(element).getElementsByTagName('*');
+ className = ' ' + className + ' ';
+
+ for (var i = 0, child, cn; child = nodes[i]; i++) {
+ if (child.className && (cn = ' ' + child.className + ' ') && (cn.include(className) ||
+ (classNames && classNames.all(function(name) {
+ return !name.toString().blank() && cn.include(' ' + name + ' ');
+ }))))
+ elements.push(Element.extend(child));
+ }
+ return elements;
+ };
+
+ return function(className, parentElement) {
+ return $(parentElement || document.body).getElementsByClassName(className);
+ };
+}(Element.Methods);
+
+/*--------------------------------------------------------------------------*/
+
+Element.ClassNames = Class.create();
+Element.ClassNames.prototype = {
+ initialize: function(element) {
+ this.element = $(element);
+ },
+
+ _each: function(iterator) {
+ this.element.className.split(/\s+/).select(function(name) {
+ return name.length > 0;
+ })._each(iterator);
+ },
+
+ set: function(className) {
+ this.element.className = className;
+ },
+
+ add: function(classNameToAdd) {
+ if (this.include(classNameToAdd)) return;
+ this.set($A(this).concat(classNameToAdd).join(' '));
+ },
+
+ remove: function(classNameToRemove) {
+ if (!this.include(classNameToRemove)) return;
+ this.set($A(this).without(classNameToRemove).join(' '));
+ },
+
+ toString: function() {
+ return $A(this).join(' ');
+ }
+};
+
+Object.extend(Element.ClassNames.prototype, Enumerable);
+
+/*--------------------------------------------------------------------------*/
+
+Element.addMethods();
\ No newline at end of file
Added: modules/security/trunk/examples/seamspace/src/main/webapp/lightbox/scriptaculous.js
===================================================================
--- modules/security/trunk/examples/seamspace/src/main/webapp/lightbox/scriptaculous.js (rev 0)
+++ modules/security/trunk/examples/seamspace/src/main/webapp/lightbox/scriptaculous.js 2010-03-25 02:33:21 UTC (rev 12264)
@@ -0,0 +1,58 @@
+// script.aculo.us scriptaculous.js v1.8.1, Thu Jan 03 22:07:12 -0500 2008
+
+// Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// For details, see the script.aculo.us web site: http://script.aculo.us/
+
+var Scriptaculous = {
+ Version: '1.8.1',
+ require: function(libraryName) {
+ // inserting via DOM fails in Safari 2.0, so brute force approach
+ document.write('<script type="text/javascript" src="'+libraryName+'"><\/script>');
+ },
+ REQUIRED_PROTOTYPE: '1.6.0',
+ load: function() {
+ function convertVersionString(versionString){
+ var r = versionString.split('.');
+ return parseInt(r[0])*100000 + parseInt(r[1])*1000 + parseInt(r[2]);
+ }
+
+ if((typeof Prototype=='undefined') ||
+ (typeof Element == 'undefined') ||
+ (typeof Element.Methods=='undefined') ||
+ (convertVersionString(Prototype.Version) <
+ convertVersionString(Scriptaculous.REQUIRED_PROTOTYPE)))
+ throw("script.aculo.us requires the Prototype JavaScript framework >= " +
+ Scriptaculous.REQUIRED_PROTOTYPE);
+
+ $A(document.getElementsByTagName("script")).findAll( function(s) {
+ return (s.src && s.src.match(/scriptaculous\.js(\?.*)?$/))
+ }).each( function(s) {
+ var path = s.src.replace(/scriptaculous\.js(\?.*)?$/,'');
+ var includes = s.src.match(/\?.*load=([a-z,]*)/);
+ (includes ? includes[1] : 'builder,effects,dragdrop,controls,slider,sound').split(',').each(
+ function(include) { Scriptaculous.require(path+include+'.js') });
+ });
+ }
+}
+
+Scriptaculous.load();
\ No newline at end of file
Added: modules/security/trunk/examples/seamspace/src/main/webapp/pictures.xhtml
===================================================================
--- modules/security/trunk/examples/seamspace/src/main/webapp/pictures.xhtml (rev 0)
+++ modules/security/trunk/examples/seamspace/src/main/webapp/pictures.xhtml 2010-03-25 02:33:21 UTC (rev 12264)
@@ -0,0 +1,77 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:s="http://jboss.com/products/seam/taglib">
+
+ <ui:composition template="template.xhtml">
+ <ui:define name="head">
+ <script type="text/javascript" src="lightbox/prototype.js"></script>
+ <script type="text/javascript" src="lightbox/scriptaculous.js?load=effects,builder"></script>
+ <script type="text/javascript" src="lightbox/lightbox.js"></script>
+ <link rel="stylesheet" href="lightbox/lightbox.css" type="text/css" media="screen" />
+ </ui:define>
+
+ <ui:define name="content">
+
+ <script type="text/javascript">
+ function confirmDelete()
+ {
+ return confirm("Are you sure you wish to delete this image? This action cannot be undone.");
+ }
+ </script>
+
+ <div class="errors"><h:messages globalOnly="true"/></div>
+
+ <s:div rendered="#{selectedMember == null}">
+ Sorry, but this member does not exist.
+ </s:div>
+
+ <s:div rendered="#{selectedMember != null}">
+
+ <h1>#{selectedMember.memberName}'s pictures</h1>
+
+ <div class="memberPictureCard">
+ <s:link view="/profile.seam" propagation="none">
+ #{selectedMember.memberName}<br/>
+ <h:graphicImage value="/content/images?id=#{selectedMember.picture.imageId}&width=90"/>
+ </s:link>
+
+ <s:span rendered="#{s:hasPermission(selectedMember, 'uploadImage')}">
+ [<s:link view="/pictureupload.xhtml" action="#{pictureAction.uploadPicture}" value="Upload picture" propagation="none"/>]
+ </s:span>
+
+ <br style="clear:both"/>
+ </div>
+
+ <div class="memberPictures">
+ <ui:repeat value="#{memberImages}" var="img">
+
+ <div class="thumbnail">
+ <a href="content/images?id=#{img.imageId}" rel="lightbox[pictureset]" title="#{img.caption}">
+ <h:graphicImage value="/content/images?id=#{img.imageId}&width=90" border="0"/>
+ </a>
+ <s:button view="/imagepermissions.seam"
+ action="#{permissionSearch.search(pictureSearch.lookupImage())}"
+ styleClass="padlock"
+ rendered="#{s:hasPermission(img, 'seam.grant-permission')}">
+ <f:param name="imageId" value="#{img.imageId}"/>
+ </s:button>
+ <s:button styleClass="trash"
+ action="#{pictureSearch.delete(pictureSearch.lookupImage())}"
+ rendered="#{s:hasPermission(img, 'delete')}"
+ onclick="if (!confirmDelete()) return false">
+ <f:param name="imageId" value="#{img.imageId}"/>
+ </s:button>
+ </div>
+
+ </ui:repeat>
+ </div>
+
+ </s:div>
+
+ </ui:define>
+
+ </ui:composition>
+</html>
Added: modules/security/trunk/examples/seamspace/src/main/webapp/pictureupload.xhtml
===================================================================
--- modules/security/trunk/examples/seamspace/src/main/webapp/pictureupload.xhtml (rev 0)
+++ modules/security/trunk/examples/seamspace/src/main/webapp/pictureupload.xhtml 2010-03-25 02:33:21 UTC (rev 12264)
@@ -0,0 +1,52 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:s="http://jboss.com/products/seam/taglib">
+
+ <ui:composition template="template.xhtml">
+ <ui:define name="content">
+ <div id="contentMain">
+ <div class="errors"><h:messages globalOnly="true"/></div>
+
+ <h3>Upload Picture</h3>
+
+ <div>
+
+ <h:form styleClass="register" enctype="multipart/form-data">
+ <s:validateAll>
+
+ <div class="formRow">
+ <h:outputLabel for="caption">Caption</h:outputLabel>
+ <h:inputText id="caption" value="#{pictureAction.memberImage.caption}"/>
+ <div class="validationError"><h:message for="caption"/></div>
+ </div>
+
+
+ <div class="formRow">
+ <h:outputLabel for="picture">Picture</h:outputLabel>
+ <s:fileUpload id="picture" data="#{pictureAction.memberImage.data}"
+ contentType="#{pictureAction.memberImage.contentType}" />
+ <div class="validationError"><h:message for="picture"/></div>
+ </div>
+
+ </s:validateAll>
+
+ <div class="buttons">
+ <h:commandButton value="Upload" action="#{pictureAction.savePicture}" styleClass="formButton"/>
+ <s:button value="Cancel" propagation="end" view="/pictures.xhtml" styleClass="formButton">
+ <f:param name="name" value="#{authenticatedMember.memberName}"/>
+ </s:button>
+ </div>
+
+ </h:form>
+
+ <br class="clear"/>
+ </div>
+ </div>
+
+ </ui:define>
+
+ </ui:composition>
+</html>
Added: modules/security/trunk/examples/seamspace/src/main/webapp/profile.xhtml
===================================================================
--- modules/security/trunk/examples/seamspace/src/main/webapp/profile.xhtml (rev 0)
+++ modules/security/trunk/examples/seamspace/src/main/webapp/profile.xhtml 2010-03-25 02:33:21 UTC (rev 12264)
@@ -0,0 +1,117 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:s="http://jboss.com/products/seam/taglib">
+
+ <ui:composition template="template.xhtml">
+ <ui:define name="content">
+
+ <div class="errors"><h:messages globalOnly="true"/></div>
+
+ <s:div rendered="#{selectedMember == null}">
+ Sorry, but this member does not exist.
+ </s:div>
+
+ <s:div rendered="#{selectedMember != null}">
+
+ <s:div id="memberCard">
+ <h1>#{selectedMember.memberName}'s profile</h1>
+
+ <s:div id="memberCardPicture" rendered="#{selectedMember.picture ne null}">
+ <h:graphicImage value="/content/images?id=#{selectedMember.picture.imageId}&width=170"/>
+ </s:div>
+
+ <div id="memberCardText">
+ <span class="tagline">"#{selectedMember.tagline}"</span><br/><br/>
+ #{selectedMember.gender.descr}<br/>
+ #{selectedMember.age}<br/>
+ #{selectedMember.location}<br/>
+ </div>
+
+ <br style="clear:both"/>
+
+ View My:
+ <s:link view="/pictures.xhtml" value="Pics">
+ <f:param name="name" value="#{selectedMember.memberName}"/>
+ </s:link>
+
+ </s:div>
+
+ <s:div id="memberBlog">
+ <div class="sectionHeader">#{selectedMember.memberName}'s latest blog entries</div>
+
+ <ui:repeat value="#{profile.latestBlogs}" var="latestBlog">
+ <div class="blogSummary">#{latestBlog.title}
+ (<s:link view="/blogentry.xhtml" value="view more">
+ <f:param name="name" value="#{selectedMember.memberName}"/>
+ <f:param name="blogId" value="#{latestBlog.blogId}"/>
+ </s:link>)
+ </div>
+ </ui:repeat>
+
+ [<s:link id="viewBlog" view="/blog.xhtml" value="View all blog entries" propagation="none">
+ <f:param name="name" value="#{selectedMember.memberName}"/>
+ </s:link>]
+
+ <s:span rendered="#{s:hasPermission(selectedMember, 'createBlog')}">
+ [<s:link id="createBlog" action="#{blog.createEntry}" value="Create new blog entry" propagation="none"/>]
+ </s:span>
+ </s:div>
+
+ <s:div id="memberFriends">
+ <div class="sectionHeader">#{selectedMember.memberName}'s friends</div>
+
+ <ui:repeat value="#{profile.friends}" var="f">
+ <div class="friend">
+
+ <s:link view="/profile.xhtml" propagation="none">
+ <f:param name="name" value="#{f.memberName}"/>
+ #{f.memberName}<br/>
+ <h:graphicImage value="/content/images?id=#{f.picture.imageId}&width=90"/>
+ </s:link>
+
+ </div>
+ </ui:repeat>
+
+ <br class="clear"/>
+
+ <s:span rendered="#{selectedMember.memberId != authenticatedMember.memberId and s:hasPermission(selectedMember, 'createFriendRequest')}">
+ [<s:link view="/friendrequest.xhtml" action="#{friendAction.createRequest}" value="Send a friend request"/>]
+ </s:span>
+
+ </s:div>
+
+ <s:div id="friendComments">
+ <div class="sectionHeader">#{selectedMember.memberName}'s friend's comments</div>
+
+ <ui:repeat value="#{profile.friendComments}" var="c">
+ <table class="friendComments">
+ <tr>
+ <td class="friendCommentor">
+ <s:link view="/profile.xhtml">
+ <f:param name="name" value="#{c.friend.memberName}"/>
+ #{c.friend.memberName}<br/>
+ <h:graphicImage value="/content/images?id=#{c.friend.picture.imageId}&width=90"/>
+ </s:link>
+ </td>
+
+ <td style="text-align: left">
+ <b>#{c.formattedCommentDate}</b><br/>
+ <p><s:formattedText value="#{c.comment}"/></p>
+ </td>
+ </tr>
+ </table>
+ </ui:repeat>
+
+ <s:span rendered="#{s:hasPermission(selectedMember, 'createFriendComment')}">
+ [<s:link view="/friendcomment.xhtml" value="Add Comment"/>]
+ </s:span>
+ </s:div>
+ </s:div>
+
+ </ui:define>
+
+ </ui:composition>
+</html>
Added: modules/security/trunk/examples/seamspace/src/main/webapp/register.xhtml
===================================================================
--- modules/security/trunk/examples/seamspace/src/main/webapp/register.xhtml (rev 0)
+++ modules/security/trunk/examples/seamspace/src/main/webapp/register.xhtml 2010-03-25 02:33:21 UTC (rev 12264)
@@ -0,0 +1,103 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:s="http://jboss.com/products/seam/taglib"
+ xmlns:rich="http://richfaces.org/rich">
+
+ <ui:composition template="template.xhtml">
+ <ui:define name="content">
+ <div id="contentMain">
+ <div class="errors"><h:messages globalOnly="true"/></div>
+
+ <p>
+ Already a member? <s:link view="/home.seam" value="Click here to log in" propagation="none"/>
+ </p>
+
+ <div id="register">
+ <div class="registerHeader">
+ JOIN SEAMSPACE HERE!
+ </div>
+
+ <h:form styleClass="register">
+ <s:validateAll>
+ <div class="formRow">
+ <h:outputLabel for="email">Email address<em>*</em></h:outputLabel>
+ <h:inputText id="email" value="#{register.member.email}" required="true" styleClass="wide"/>
+ <div class="validationError"><h:message for="email"/></div>
+ </div>
+
+ <div class="formRow">
+ <h:outputLabel for="firstName">First name<em>*</em></h:outputLabel>
+ <h:inputText id="firstName" value="#{register.member.firstName}" required="true"/>
+ <div class="validationError"><h:message for="firstName"/></div>
+ </div>
+
+ <div class="formRow">
+ <h:outputLabel for="lastName">Last name<em>*</em></h:outputLabel>
+ <h:inputText id="lastName" value="#{register.member.lastName}" required="true"/>
+ <div class="validationError"><h:message for="lastName"/></div>
+ </div>
+
+ <div class="formRow">
+ <h:outputLabel for="memberName">Nick name<em>*</em></h:outputLabel>
+ <h:inputText id="memberName" value="#{register.member.memberName}" required="true"/>
+ <div class="validationError"><h:message for="memberName"/></div>
+ </div>
+
+ <div class="formRow">
+ <h:outputLabel for="username">Username<em>*</em></h:outputLabel>
+ <h:inputText id="username" value="#{register.username}" required="true"/>
+ <div class="validationError"><h:message for="username"/></div>
+ </div>
+
+ <div class="formRow">
+ <h:outputLabel for="password">Password<em>*</em></h:outputLabel>
+ <h:inputSecret id="password" value="#{register.password}" required="true"/>
+ <div class="validationError"><h:message for="password"/></div>
+ </div>
+
+ <div class="formRow">
+ <h:outputLabel for="confirmPassword">Confirm password<em>*</em></h:outputLabel>
+ <h:inputSecret id="confirmPassword" value="#{register.confirm}" required="true"/>
+ <div class="validationError"><h:message for="confirmPassword"/></div>
+ </div>
+
+ <div class="formRow">
+ <h:outputLabel for="gender">Gender<em>*</em></h:outputLabel>
+ <h:selectOneRadio id="gender" value="#{register.gender}" required="true">
+ <f:selectItem itemValue="Male" itemLabel="Male" />
+ <f:selectItem itemValue="Female" itemLabel="Female" />
+ </h:selectOneRadio>
+ <div class="validationError"><h:message for="gender"/></div>
+ </div>
+
+ <div class="formRow">
+ <h:outputLabel for="dob">Date of birth<em>*</em></h:outputLabel>
+ <rich:calendar id="dob" value="#{register.member.dob}" required="true" datePattern="MM/dd/yyyy" buttonIcon="images/ellipsis.png" />
+ <div class="validationError"><h:message for="dob"/></div>
+ </div>
+
+ <div class="formRow">
+ <h:outputLabel for="verifyCaptcha"><h:graphicImage value="/seam/resource/captcha"/><em>*</em></h:outputLabel>
+ <h:inputText id="verifyCaptcha" value="#{captcha.response}" required="true"/>
+ <div class="validationError"><h:message for="verifyCaptcha"/></div>
+ </div>
+
+ </s:validateAll>
+
+ <div class="buttons">
+ <h:commandButton value="Next" action="#{register.next}" styleClass="registerButton"/>
+ </div>
+
+ </h:form>
+
+ <br class="clear"/>
+ </div>
+ </div>
+
+ </ui:define>
+
+ </ui:composition>
+</html>
Added: modules/security/trunk/examples/seamspace/src/main/webapp/register2.xhtml
===================================================================
--- modules/security/trunk/examples/seamspace/src/main/webapp/register2.xhtml (rev 0)
+++ modules/security/trunk/examples/seamspace/src/main/webapp/register2.xhtml 2010-03-25 02:33:21 UTC (rev 12264)
@@ -0,0 +1,42 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:s="http://jboss.com/products/seam/taglib">
+
+ <ui:composition template="template.xhtml">
+ <ui:define name="content">
+ <div id="contentMain">
+ <div class="errors"><h:messages globalOnly="true"/></div>
+
+ <div id="register">
+ <div class="registerHeader">
+ JOIN SEAMSPACE HERE!
+ </div>
+
+ <h:form styleClass="register" enctype="multipart/form-data">
+ <s:validateAll>
+
+ <div class="formRow">
+ <h:outputLabel for="picture">Member photo</h:outputLabel>
+ <s:fileUpload id="picture" data="#{register.picture}" accept="image/png"
+ contentType="#{register.pictureContentType}" />
+ <div class="validationError"><h:message for="picture"/></div>
+ </div>
+
+ </s:validateAll>
+
+ <div class="buttons">
+ <h:commandButton value="Upload" action="#{register.uploadPicture}" styleClass="registerButton"/>
+ </div>
+
+ </h:form>
+
+ <br class="clear"/>
+ </div>
+ </div>
+
+ </ui:define>
+
+ </ui:composition>
+</html>
Added: modules/security/trunk/examples/seamspace/src/main/webapp/roledetail.page.xml
===================================================================
--- modules/security/trunk/examples/seamspace/src/main/webapp/roledetail.page.xml (rev 0)
+++ modules/security/trunk/examples/seamspace/src/main/webapp/roledetail.page.xml 2010-03-25 02:33:21 UTC (rev 12264)
@@ -0,0 +1,9 @@
+<page xmlns="http://jboss.com/products/seam/pages"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://jboss.com/products/seam/pages http://jboss.com/products/seam/pages-2.2.xsd">
+ <navigation from-action="#{roleAction.save}">
+ <rule if-outcome="success">
+ <redirect view-id="/rolemanager.xhtml"/>
+ </rule>
+ </navigation>
+</page>
Added: modules/security/trunk/examples/seamspace/src/main/webapp/roledetail.xhtml
===================================================================
--- modules/security/trunk/examples/seamspace/src/main/webapp/roledetail.xhtml (rev 0)
+++ modules/security/trunk/examples/seamspace/src/main/webapp/roledetail.xhtml 2010-03-25 02:33:21 UTC (rev 12264)
@@ -0,0 +1,55 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:rich="http://richfaces.org/rich"
+ xmlns:s="http://jboss.com/products/seam/taglib">
+
+ <ui:composition template="template.xhtml">
+
+ <ui:define name="head">
+ <link href="style/security.css" rel="stylesheet" type="text/css"/>
+ </ui:define>
+
+ <ui:define name="content">
+
+ <div id="contentMain">
+
+ <h2>Role Details</h2>
+
+ <h:messages globalOnly="true"/>
+
+ <h:form id="role">
+
+ <div class="formRow">
+ <h:outputLabel for="role" value="Role" styleClass="formLabel"/>
+ <h:inputText id="name" value="#{roleAction.role}" readonly="#{identityManager.userExists(roleAction.role)}"/>
+ <div class="validationError"><h:message for="role"/></div>
+ </div>
+
+ <div class="formRow">
+ <h:outputLabel for="groups" value="Member of" styleClass="formLabel"/>
+ <div class="selectMany">
+ <h:selectManyCheckbox id="roles" value="#{roleAction.groups}" layout="pageDirection" styleClass="roles">
+ <s:selectItems value="#{roleAction.assignableRoles}" var="role" label="#{role}"/>
+ </h:selectManyCheckbox>
+ </div>
+ <div class="validationError"><h:message for="groups"/></div>
+ </div>
+
+ <div class="formButtons">
+ <h:commandButton id="save" value="Save" action="#{roleAction.save}" styleClass="formButton"/>
+ <s:button id="cancel" view="/rolemanager.xhtml" value="Cancel" propagation="end" styleClass="formButton"/>
+ </div>
+
+ <br class="clear"/>
+
+ </h:form>
+
+ </div>
+
+ </ui:define>
+
+ </ui:composition>
+</html>
Added: modules/security/trunk/examples/seamspace/src/main/webapp/rolemanager.page.xml
===================================================================
--- modules/security/trunk/examples/seamspace/src/main/webapp/rolemanager.page.xml (rev 0)
+++ modules/security/trunk/examples/seamspace/src/main/webapp/rolemanager.page.xml 2010-03-25 02:33:21 UTC (rev 12264)
@@ -0,0 +1,14 @@
+<page xmlns="http://jboss.com/products/seam/pages"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://jboss.com/products/seam/pages http://jboss.com/products/seam/pages-2.2.xsd"
+ action="#{roleSearch.loadRoles}">
+ <restrict>#{s:hasPermission('seam.role', 'read')}</restrict>
+
+ <navigation from-action="#{roleAction.createRole}">
+ <redirect view-id="/roledetail.xhtml"/>
+ </navigation>
+
+ <navigation from-action="#{roleAction.editRole(roleSearch.selectedRole)}">
+ <redirect view-id="/roledetail.xhtml"/>
+ </navigation>
+</page>
Added: modules/security/trunk/examples/seamspace/src/main/webapp/rolemanager.xhtml
===================================================================
--- modules/security/trunk/examples/seamspace/src/main/webapp/rolemanager.xhtml (rev 0)
+++ modules/security/trunk/examples/seamspace/src/main/webapp/rolemanager.xhtml 2010-03-25 02:33:21 UTC (rev 12264)
@@ -0,0 +1,61 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:s="http://jboss.com/products/seam/taglib">
+
+ <ui:composition template="template.xhtml">
+
+ <ui:define name="head">
+ <link href="style/security.css" rel="stylesheet" type="text/css"/>
+ </ui:define>
+
+ <ui:define name="content">
+
+ <script type="text/javascript">
+ function confirmDelete()
+ {
+ return confirm("Are you sure you wish to delete this role? This action cannot be undone.");
+ }
+ </script>
+
+ <div id="contentMain">
+
+ <h2>Role Manager</h2>
+
+ <s:button id="newRole" action="#{roleAction.createRole}" styleClass="newrole" rendered="#{s:hasPermission('seam.account', 'create', null)}"/>
+
+ <h:dataTable
+ id="threads"
+ value="#{roles}"
+ var="role"
+ styleClass="security"
+ cellspacing="0"
+ headerClass="header"
+ rowClasses="odd,even"
+ columnClasses=",,action">
+ <h:column width="auto">
+ <f:facet name="header">Role</f:facet>
+ #{role}
+ </h:column>
+ <h:column id="roles" width="auto">
+ <f:facet name="header">Member Of</f:facet>
+ #{roleSearch.getRoleGroups(role)}
+ </h:column>
+ <h:column width="auto">
+ <f:facet name="header">Action</f:facet>
+ <s:fragment rendered="#{s:hasPermission('seam.role', 'update')}">
+ <s:link id="edit" value="Edit" action="#{roleAction.editRole(roleSearch.selectedRole)}"/><span> | </span>
+ </s:fragment>
+ <s:link id="delete" value="Delete" action="#{identityManager.deleteRole(roleSearch.selectedRole)}"
+ rendered="#{s:hasPermission('seam.role', 'delete')}"
+ onclick="return confirmDelete()"/>
+ </h:column>
+ </h:dataTable>
+ </div>
+
+ </ui:define>
+
+ </ui:composition>
+</html>
Added: modules/security/trunk/examples/seamspace/src/main/webapp/security.xhtml
===================================================================
--- modules/security/trunk/examples/seamspace/src/main/webapp/security.xhtml (rev 0)
+++ modules/security/trunk/examples/seamspace/src/main/webapp/security.xhtml 2010-03-25 02:33:21 UTC (rev 12264)
@@ -0,0 +1,28 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:s="http://jboss.com/products/seam/taglib">
+
+ <ui:composition template="template.xhtml">
+
+ <ui:define name="head">
+ <link href="style/security.css" rel="stylesheet" type="text/css"/>
+ </ui:define>
+
+ <ui:define name="content">
+
+ <div id="contentMain">
+
+ <h2>Security</h2>
+
+ <s:button id="manageUsers" view="/usermanager.xhtml" styleClass="manageusers" value="Manage Users"/><br/>
+ <s:button id="manageRoles" view="/rolemanager.xhtml" styleClass="manageroles" value="Manage Roles"/>
+
+ </div>
+
+ </ui:define>
+
+ </ui:composition>
+</html>
Added: modules/security/trunk/examples/seamspace/src/main/webapp/security_error.xhtml
===================================================================
--- modules/security/trunk/examples/seamspace/src/main/webapp/security_error.xhtml (rev 0)
+++ modules/security/trunk/examples/seamspace/src/main/webapp/security_error.xhtml 2010-03-25 02:33:21 UTC (rev 12264)
@@ -0,0 +1,17 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:s="http://jboss.com/products/seam/taglib">
+
+ <ui:composition template="template.xhtml">
+ <ui:define name="content">
+
+ <h1>A Security Error has occurred</h1>
+
+ <div class="errors"><h:messages globalOnly="true"/></div>
+
+ </ui:define>
+
+ </ui:composition>
+</html>
Added: modules/security/trunk/examples/seamspace/src/main/webapp/style/advertising.png
===================================================================
(Binary files differ)
Property changes on: modules/security/trunk/examples/seamspace/src/main/webapp/style/advertising.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: modules/security/trunk/examples/seamspace/src/main/webapp/style/btn_newpermission.png
===================================================================
(Binary files differ)
Property changes on: modules/security/trunk/examples/seamspace/src/main/webapp/style/btn_newpermission.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: modules/security/trunk/examples/seamspace/src/main/webapp/style/btn_newrole.png
===================================================================
(Binary files differ)
Property changes on: modules/security/trunk/examples/seamspace/src/main/webapp/style/btn_newrole.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: modules/security/trunk/examples/seamspace/src/main/webapp/style/btn_newuser.png
===================================================================
(Binary files differ)
Property changes on: modules/security/trunk/examples/seamspace/src/main/webapp/style/btn_newuser.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: modules/security/trunk/examples/seamspace/src/main/webapp/style/cal-next.png
===================================================================
(Binary files differ)
Property changes on: modules/security/trunk/examples/seamspace/src/main/webapp/style/cal-next.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: modules/security/trunk/examples/seamspace/src/main/webapp/style/cal-prev.png
===================================================================
(Binary files differ)
Property changes on: modules/security/trunk/examples/seamspace/src/main/webapp/style/cal-prev.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: modules/security/trunk/examples/seamspace/src/main/webapp/style/date.css
===================================================================
--- modules/security/trunk/examples/seamspace/src/main/webapp/style/date.css (rev 0)
+++ modules/security/trunk/examples/seamspace/src/main/webapp/style/date.css 2010-03-25 02:33:21 UTC (rev 12264)
@@ -0,0 +1,185 @@
+div.seam-date
+{
+ margin-top: 5px;
+ border: 1px solid #AAAAAA;
+ background: #fff url(../img/input.bg.gif) 0 0 repeat-x;
+ background-color: #FFFFFF;
+ color: #505050;
+ font-family: Tahoma, Arial, Helvetica, sans-serif;
+ font-size: 12px;
+}
+
+table.seam-date td {
+ font-family: Tahoma, Arial, Helvetica, sans-serif;
+ font-weight: 11px;
+}
+
+.seam-date-monthNames
+{
+ width: 70px;
+ border: 1px solid #dddddd;
+ border-right: 3px solid #444444;
+ border-bottom: 3px solid #444444;
+ background-color: #ffffff;
+ font-size: 12px;
+ cursor: pointer;
+ font-family: Tahoma, Arial, Helvetica, sans-serif;
+ font-weight: normal;
+}
+
+a.seam-date-monthNameLink, a.seam-date-monthNameLink:visited
+{
+ text-align: center;
+ display: block;
+ color: #555555;
+}
+
+a.seam-date-monthNameLink:hover
+{
+ background-color: #CCCCCC;
+ color: red;
+}
+
+.seam-date-years
+{
+ height: 10em;
+ overflow: auto;
+ width: 60px;
+ border: 1px solid #dddddd;
+ border-right: 3px solid #444444;
+ border-bottom: 3px solid #444444;
+ background-color: #ffffff;
+ font-size: 12px;
+ cursor: pointer;
+ font-family: Tahoma, Arial, Helvetica, sans-serif;
+ font-weight: normal;
+}
+
+a.seam-date-yearLink, a.seam-date-yearLink:visited
+{
+ text-align: center;
+ display: block;
+ color: #555555;
+}
+
+a.seam-date-yearLink:hover
+{
+ background-color: #CCCCCC;
+ color: red;
+}
+
+tr.seam-date-header
+{
+ padding: 2px 0px 2px 0px;
+}
+
+td.seam-date-header
+{
+ padding: 0px 8px 0px 8px;
+ text-align: center;
+ color: gray;
+ font-family: Tahoma, Arial, Helvetica, sans-serif;
+ font-weight: bold;
+ font-size: 12px;
+}
+
+td.seam-date-header-prevMonth
+{
+ background-image: url("cal-prev.png");
+ background-repeat: no-repeat;
+ background-position: center;
+ padding: 0px 2px 0px 2px;
+ width: 17px;
+ height: 16px;
+ margin-left: 2px;
+}
+
+td.seam-date-header-nextMonth
+{
+ background-image: url("cal-next.png");
+ background-repeat: no-repeat;
+ background-position: center;
+ padding: 0px 2px 0px 2px;
+ width: 17px;
+ height: 16px;
+ margin-right: 2px;
+}
+
+tr.seam-date-headerDays
+{
+ color: white;
+ font-weight: normal;
+}
+
+tr.seam-date-headerDays > td
+{
+ background-color: #CCCCCC;
+ border: 1px solid #AAAAAA;
+ color: white;
+ text-align: center;
+ width: 26px;
+}
+
+tr.seam-date-footer
+{
+ background-color: white;
+ color: #505050;
+ font-weight: bold;
+}
+
+tr.seam-date-footer > td
+{
+ text-align: center;
+}
+
+td.seam-date-inMonth
+{
+ background-color: white;
+ color: black;
+ font-weight: normal;
+ cursor: pointer;
+ border: 1px solid #ece9d8;
+}
+
+td.seam-date-outMonth
+{
+ background-color: white;
+ color: #999999;
+ font-weight: normal;
+ cursor: pointer;
+ border: 1px solid #ece9d8;
+}
+
+td.seam-date-selected
+{
+ background-color: #CCCCCC;
+ border: 1px solid #AAAAAA;
+ color: black;
+ font-weight: normal;
+}
+
+td.seam-date-dayOff-inMonth
+{
+ background-color: #efefef;
+ color: black;
+ font-weight: normal;
+ cursor: pointer;
+ border: 1px solid #ece9d8;
+}
+
+td.seam-date-dayOff-outMonth
+{
+ background-color: #efefef;
+ color: #999999;
+ font-weight: normal;
+ cursor: pointer;
+ border: 1px solid #ece9d8;
+}
+
+td.seam-date-hover
+{
+ background-color: #CCCCCC;
+ border: 1px solid #AAAAAA;
+ cursor: pointer;
+ color: red;
+}
\ No newline at end of file
Added: modules/security/trunk/examples/seamspace/src/main/webapp/style/divider.png
===================================================================
(Binary files differ)
Property changes on: modules/security/trunk/examples/seamspace/src/main/webapp/style/divider.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: modules/security/trunk/examples/seamspace/src/main/webapp/style/manage_roles.png
===================================================================
(Binary files differ)
Property changes on: modules/security/trunk/examples/seamspace/src/main/webapp/style/manage_roles.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: modules/security/trunk/examples/seamspace/src/main/webapp/style/manage_users.png
===================================================================
(Binary files differ)
Property changes on: modules/security/trunk/examples/seamspace/src/main/webapp/style/manage_users.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: modules/security/trunk/examples/seamspace/src/main/webapp/style/padlock.png
===================================================================
(Binary files differ)
Property changes on: modules/security/trunk/examples/seamspace/src/main/webapp/style/padlock.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: modules/security/trunk/examples/seamspace/src/main/webapp/style/seamspace.css
===================================================================
--- modules/security/trunk/examples/seamspace/src/main/webapp/style/seamspace.css (rev 0)
+++ modules/security/trunk/examples/seamspace/src/main/webapp/style/seamspace.css 2010-03-25 02:33:21 UTC (rev 12264)
@@ -0,0 +1,600 @@
+body {
+ font-family: verdana, arial, sans-serif, helvetica;
+ background-color: #e5e5e5;
+ font-size:11px;
+ margin: 0;
+}
+
+h1, h2, h3 {
+ margin-top: 2px;
+ margin-bottom: 6px;
+}
+
+#header {
+ margin-left: auto;
+ margin-right: auto;
+ background: url(seamspace.png) left top no-repeat;
+ height: 100px;
+ width: 800px;
+ background-color: #003399;
+}
+
+#menubar {
+ margin-left: auto;
+ margin-right: auto;
+ overflow: none;
+ height: 17px;
+ width: 800px;
+ background-color: #5a8cc0;
+ text-align: center;
+ padding-top: 3px;
+}
+
+#content {
+ padding-top: 10px;
+ margin-left: auto;
+ margin-right: auto;
+ width: 800px;
+ background-color: #ffffff;
+ min-height: 800px;
+}
+
+#content a, #content a:visited {
+ font-weight: bold;
+ color: #003399;
+}
+
+#content a:hover {
+ font-weight: bold;
+ color: #7799dd;
+}
+
+#contentMain {
+ float: left;
+ width: 430px;
+ margin-left: 10px;
+ margin-top: 10px;
+}
+
+#contentDivider {
+ float: left;
+ background: url(divider.png) repeat-y top left;
+ height: 100%;
+ width: 10px;
+}
+
+#contentSide {
+ float: left;
+ width: 310px;
+ margin-left: 10px;
+ margin-top: 10px;
+ margin-right: 10px;
+}
+
+#memberCard {
+ width: 350px;
+ float: left;
+ margin-left: 10px;
+ border: 2px solid #eeeeee;
+ background-color: #f5f5f5;
+ padding: 2px;
+}
+
+#memberCardPicture {
+ width: 170px;
+ float: left;
+}
+
+#memberCardText {
+ width: 170px;
+ float: right;
+}
+
+#memberBlog {
+ width: 400px;
+ float: right;
+ margin-right: 10px;
+ border: 2px solid #eeeeee;
+ padding: 2px;
+}
+
+#blogMemberCard {
+ width: 140px;
+ float: left;
+ margin-left: 10px;
+ border: 2px solid #eeeeee;
+ background-color: #f5f5f5;
+ padding: 2px;
+ text-align: center;
+}
+
+#blog {
+ float: right;
+ width: 600px;
+ margin-right: 10px;
+ padding: 2px;
+}
+
+#memberFriends {
+ width: 400px;
+ float: right;
+ margin-right: 10px;
+ margin-top: 12px;
+ border: 2px solid #eeeeee;
+ padding: 2px;
+}
+
+div.friend {
+ float: left;
+ width: 99px;
+ text-align: center;
+}
+
+#friendComments {
+ width: 400px;
+ float: right;
+ margin-right: 10px;
+ margin-top: 12px;
+ border: 2px solid #eeeeee;
+ padding: 2px;
+}
+
+table.friendComments {
+ width: 100%;
+}
+
+table.friendComments td {
+ border: 1px solid #dddddd;
+ background-color: #eeeeee;
+ text-align: center;
+ vertical-align: top;
+}
+
+td.friendCommentor {
+ width: 100px;
+}
+
+div.friendRequest {
+ background-color: #bbddff;
+ width: 600px;
+ float: right;
+ margin-right: 10px;
+ border: 2px solid #eeeeee;
+ padding: 4px;
+}
+
+div.friendRequest textarea {
+ font-family: verdana, arial, sans-serif, helvetica;
+ font-size:11px;
+ margin: 4px 12px 8px 0px;
+ width: 560px;
+ height: 120px;
+}
+
+div.blogSummary {
+ padding: 0px 2px 4px 2px;
+ margin-bottom: 8px;
+}
+
+div.blogEntry {
+ background-color: #bbddff;
+ padding: 8px 8px 8px 8px;
+ margin-bottom: 12px;
+}
+
+div.blogEntry label {
+ font-weight: bold;
+}
+
+div.blogEntry input.title {
+ width: 560px;
+}
+
+div.blogEntry textarea {
+ font-family: verdana, arial, sans-serif, helvetica;
+ font-size:11px;
+ margin: 4px 12px 8px 0px;
+ width: 560px;
+ height: 120px;
+}
+
+div.blogDate {
+ font-weight: bold;
+ margin-bottom: 8px;
+}
+
+div.blogTitle {
+ font-weight: bold;
+ margin-left: 24px;
+ margin-bottom: 8px;
+}
+
+div.blogText {
+ margin-left: 24px;
+ margin-bottom: 8px;
+ text-align: justify;
+}
+
+div.blogFooter {
+ margin-bottom: 8px;
+}
+
+table.blogComment {
+ margin-bottom: 2px;
+ width: 100%;
+}
+
+td.blogCommentor {
+ width: 160px;
+ background-color: #ff9933;
+ text-align: center;
+ vertical-align: top;
+}
+
+td.blogCommentText {
+ background-color: #ffddbb;
+ padding: 12px 4px 4px 8px;
+}
+
+div.commentEntry {
+ background-color: #ff9933;
+ padding: 4px 4px 4px 4px;
+}
+
+div.commentEntry label {
+ font-weight: bold;
+ color: #ffffff;
+ margin-bottom: 4px;
+}
+
+div.commentEntry textarea {
+ font-family: verdana, arial, sans-serif, helvetica;
+ font-size:11px;
+ margin: 8px 12px 8px 6px;
+ width: 560px;
+ height: 120px;
+}
+
+div.buttons {
+ float: right;
+}
+
+input.action {
+ display: inline;
+ margin-right: 8px;
+ margin-top: 4px;
+ margin-bottom: 4px;
+ border: 1px solid #003399;
+ background-color: #ffffff;
+ color: #003399;
+ font-size: 10px;
+ padding: 3px 8px 3px 8px;
+}
+
+div.headerRight {
+ float: right;
+ width: 440px;
+ padding-right: 4px;
+ padding-top: 4px;
+}
+
+div.headerMenu {
+ float: right;
+}
+
+div.advertising {
+ background: url(advertising.png) no-repeat top left;
+ width: 307px;
+ height: 86px;
+}
+
+div.sectionHeader {
+ font-weight: bold;
+ font-size: normal;
+ background-color: #eeeeee;
+ padding: 2px 2px 2px 2px;
+ margin-bottom: 12px;
+}
+
+span.tagline {
+ font-style: italic;
+}
+
+a, a:visited, a:hover {
+ color: #ffffff;
+ text-decoration: none;
+ padding-left: 2px;
+ padding-right: 2px;
+}
+
+#header a:hover {
+ text-decoration: underline;
+}
+
+#search {
+ margin-top: 2px;
+}
+
+#search a:hover {
+ margin-bottom: 4px;
+ text-decoration: none;
+}
+
+input.searchField {
+ width: 290px;
+}
+
+input.searchButton {
+ width: 140px;
+}
+
+#menubar a:hover {
+ color: #003399;
+ text-decoration: underline;
+}
+
+div.memberLogin {
+ margin-top: 16px;
+ width: 300px;
+ border: 1px solid #003399;
+ padding: 0px;
+}
+
+div.loginHeader {
+ color: #ffffff;
+ font-weight: bold;
+ background-color: #003399;
+ height: 18px;
+ padding: 2px 2px 2px 2px;
+}
+
+div.newMembers {
+ width: 300px;
+ margin-top: 8px;
+ border: 1px solid #ffcc99;
+}
+
+div.newMembersHeader {
+ font-weight: bold;
+ background-color: #ffcc99;
+ height: 18px;
+ padding: 2px 2px 2px 2px;
+}
+
+div.newMember {
+ float: left;
+ width: 99px;
+ text-align: center;
+}
+
+div.newMember img {
+ border: none;
+}
+
+div.loginRow {
+ padding-top: 2px;
+ padding-bottom: 2px;
+}
+
+label.loginLabel {
+ float: left;
+ width: 100px;
+ padding: 2px 2px 2px 2px;
+}
+
+div.buttons {
+ float: right;
+ margin-right: 60px;
+}
+
+input.loginButton {
+ display: inline;
+ margin-right: 8px;
+ margin-top: 4px;
+ margin-bottom: 4px;
+ border: 1px solid #003399;
+ background-color: #ffffff;
+ color: #003399;
+ font-size: 10px;
+ padding: 3px 8px 3px 8px;
+}
+
+input.registerButton {
+ display: inline;
+ margin-top: 4px;
+ margin-bottom: 4px;
+ border: 1px solid #ffa76d;
+ background-color: #ff6600;
+ color: #ffffff;
+ font-size: 10px;
+ padding: 3px 8px 3px 8px;
+}
+
+div.loginRow input[type='text'], div.loginRow input[type='password'] {
+ width: 180px;
+}
+
+.clear {
+ clear: both;
+ font-size: 0px;
+}
+
+.divider {
+ color: #aaaaaa;
+}
+
+div.errors {
+ color: #ff0000;
+ font-weight: bold;
+ font-size: normal;
+}
+
+div.errors ul {
+ list-style: none;
+}
+
+#register {
+ float: left;
+ width: 400px;
+ border: 1px solid #5a8cc0;
+}
+
+div.registerHeader {
+ font-size: normal;
+ font-weight: bold;
+ color: #ffffff;
+ background-color: #5a8cc0;
+ padding: 8px 4px 8px 12px;
+}
+
+form.register label {
+ float: left;
+ display: block;
+ vertical-align: top;
+ width: 120px;
+ margin-top: 2px;
+}
+
+form.register input.wide {
+ width: 240px;
+}
+
+form.register em {
+ font-size: normal;
+ font-weight: bold;
+ color: #ff0000;
+}
+
+form.register div.validationError {
+ margin-left: 120px;
+ font-weight: bold;
+ color: #ff0000;
+}
+
+img.ellipsis {
+ width: 18px;
+ height: 18px;
+ border: none;
+ margin-bottom: 2px;
+ margin-left: 2px;
+ vertical-align: bottom;
+ cursor: pointer;
+}
+
+div.seam-date {
+ background-color: #ffffff;
+ border: 1px solid #5a8cc0;
+}
+
+td.seam-date-hover {
+ background-color: #5a8cc0;
+ color: #ffffff;
+ cursor: pointer;
+}
+
+quote {
+ border: 1px solid #fac289;
+ margin: 4px 8px 4px 8px;
+ padding: 12px 12px 12px 12px;
+ background-color: #fbf4ec;
+ display: block;
+}
+
+/* General form styles */
+
+div.formRow {
+ padding: 3px 4px 3px 2px;
+ clear: both;
+}
+
+div.formRow label {
+ float: left;
+ width: 120px;
+ padding: 2px 2px 2px 2px;
+}
+
+div.formRow input[type='text'] {
+ width: 120px;
+}
+
+div.formRow input[type='password'] {
+ width: 120px;
+}
+
+div.validationError {
+ margin-left: 120px;
+ font-weight: bold;
+ color: #ff0000;
+}
+
+.roles {
+ width: 120px;
+ border: 1px solid #7F9DB9;
+ background-color: #E7EDF7;
+}
+
+div.selectMany label {
+ float: none;
+}
+
+.formButton {
+ background: url(../images/bg_button.png) top left repeat-x;
+ border: 1px solid #003399;
+ font-size: small;
+ font-weight: bold;
+ color: #000000;
+ margin-right: 8px;
+ padding-left: 4px;
+ padding-right: 4px;
+}
+
+div.formButtons {
+ float: right;
+ padding: 4px 8px 16px 2px;
+}
+
+div.memberPictures {
+ float: right;
+ width: 600px;
+ margin-right: 10px;
+ padding: 2px;
+ background-color: #000000;
+ border: 1px solid #aaaaaa;
+ padding: 8px 8px 8px 8px;
+}
+
+div.memberPictureCard {
+ width: 140px;
+ float: left;
+ margin-left: 10px;
+ border: 2px solid #eeeeee;
+ background-color: #f5f5f5;
+ padding: 2px;
+ text-align: center;
+}
+
+div.thumbnail {
+ width: 110px;
+ background-color: #333333;
+ padding: 10px 10px 10px 10px;
+ margin: 8px 8px 8px 8px;
+ float: left;
+ text-align: center;
+}
+
+input.padlock {
+ background: url(padlock.png) top left no-repeat;
+ width: 14px;
+ height: 20px;
+ float: left;
+ border: 0px;
+ margin-left: 10px;
+}
+
+input.trash {
+ background: url(trash.png) top left no-repeat;
+ width: 20px;
+ height: 20px;
+ float: left;
+ border: 0px;
+}
\ No newline at end of file
Added: modules/security/trunk/examples/seamspace/src/main/webapp/style/seamspace.png
===================================================================
(Binary files differ)
Property changes on: modules/security/trunk/examples/seamspace/src/main/webapp/style/seamspace.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: modules/security/trunk/examples/seamspace/src/main/webapp/style/security.css
===================================================================
--- modules/security/trunk/examples/seamspace/src/main/webapp/style/security.css (rev 0)
+++ modules/security/trunk/examples/seamspace/src/main/webapp/style/security.css 2010-03-25 02:33:21 UTC (rev 12264)
@@ -0,0 +1,126 @@
+input.newuser {
+ background: url(btn_newuser.png) top left no-repeat;
+ height: 39px;
+ width: 113px;
+ margin: 4px 4px 4px 4px;
+ border: 0px;
+ cursor: pointer;
+}
+
+input.newrole {
+ background: url(btn_newrole.png) top left no-repeat;
+ height: 39px;
+ width: 113px;
+ margin: 4px 4px 4px 4px;
+ border: 0px;
+ cursor: pointer;
+}
+
+input.newpermission {
+ background: url(btn_newpermission.png) top left no-repeat;
+ height: 39px;
+ width: 113px;
+ margin: 4px 4px 4px 4px;
+ border: 0px;
+ cursor: pointer;
+}
+
+input.manageusers {
+ display: block;
+ background: url(manage_users.png) top left no-repeat;
+ height: 88px;
+ width: 300px;
+ padding-left: 10px;
+ font-size: 19px;
+ font-weight: bold;
+ color: #333333;
+ border: 0px;
+ cursor: pointer;
+ margin-top: 20px;
+ margin-left: 20px;
+}
+
+input.manageroles {
+ display: block;
+ background: url(manage_roles.png) top left no-repeat;
+ height: 88px;
+ width: 300px;
+ padding-left: 10px;
+ font-size: 19px;
+ font-weight: bold;
+ color: #333333;
+ border: 0px;
+ cursor: pointer;
+ margin-top: 20px;
+ margin-left: 20px;
+}
+
+.roles {
+ width: 120px;
+ border: 1px solid #7F9DB9;
+ background-color: #E7EDF7;
+}
+
+div.selectMany label {
+ float: none;
+}
+
+.formButton {
+ background: url(../images/bg_button.png) top left repeat-x;
+ border: 1px solid #003399;
+ font-size: small;
+ font-weight: bold;
+ color: #000000;
+ margin-right: 8px;
+ padding-left: 4px;
+ padding-right: 4px;
+}
+
+div.formButtons {
+ float: right;
+ padding: 4px 8px 16px 2px;
+}
+
+div.checkmark {
+ background: url(../images/checkmark.png) top left no-repeat;
+ width: 14px;
+ height: 15px;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+div.cross {
+ background: url(../images/cross.png) top left no-repeat;
+ width: 14px;
+ height: 15px;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+table.security {
+ border: 1px solid black;
+ width: 500px;
+}
+
+th.header {
+ background: url(table_header.png) top left repeat-x;
+ color: #ffffff;
+ padding-top: 3px;
+ padding-bottom: 3px;
+}
+
+tr.odd {
+ background-color: #ffffff;
+}
+
+tr.even {
+ background-color: #E9F5FF;
+}
+
+td.enabled {
+ text-align: center;
+}
+
+td.action {
+ text-align: right;
+}
\ No newline at end of file
Added: modules/security/trunk/examples/seamspace/src/main/webapp/style/table_header.png
===================================================================
(Binary files differ)
Property changes on: modules/security/trunk/examples/seamspace/src/main/webapp/style/table_header.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: modules/security/trunk/examples/seamspace/src/main/webapp/style/trash.png
===================================================================
(Binary files differ)
Property changes on: modules/security/trunk/examples/seamspace/src/main/webapp/style/trash.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: modules/security/trunk/examples/seamspace/src/main/webapp/template.xhtml
===================================================================
--- modules/security/trunk/examples/seamspace/src/main/webapp/template.xhtml (rev 0)
+++ modules/security/trunk/examples/seamspace/src/main/webapp/template.xhtml 2010-03-25 02:33:21 UTC (rev 12264)
@@ -0,0 +1,66 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:s="http://jboss.com/products/seam/taglib"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:f="http://java.sun.com/jsf/core">
+
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
+ <title>SeamSpace</title>
+ <link href="style/seamspace.css" rel="stylesheet" type="text/css"/>
+ <link href="style/date.css" rel="stylesheet" type="text/css"/>
+ <ui:insert name="head"/>
+</head>
+
+<body>
+
+ <div id="header">
+ <div class="headerRight">
+ <div class="headerMenu">
+
+ <s:fragment rendered="#{identity.loggedIn}">
+ <s:link id="profile" view="/profile.xhtml" value="My Profile" propagation="none">
+ <f:param name="name" value="#{authenticatedMember.memberName}"/>
+ </s:link>
+ <h:outputText styleClass="divider" value=" | "/>
+ </s:fragment>
+
+ <s:fragment rendered="#{s:hasRole('admin')}">
+ <s:link id="security" view="/security.xhtml" value="Security" propagation="none"/>
+ <h:outputText styleClass="divider" value=" | "/>
+ </s:fragment>
+
+ <s:link id="logout" action="#{identity.logout}" value="Log out" rendered="#{identity.loggedIn}"/>
+ <h:outputLink id="login" value="home.seam" rendered="#{not identity.loggedIn}">Log in</h:outputLink>
+ </div>
+ <br style="clear:both"/>
+ <h:form>
+ <div>
+ <a href="#">SeamSpace</a><h:outputText styleClass="divider" value=" | "/>
+ <a href="#">People</a><h:outputText styleClass="divider" value=" | "/>
+ <a href="#">Music</a><h:outputText styleClass="divider" value=" | "/>
+ <a href="#">Blogs</a>
+ </div>
+ <div id="search">
+ <h:inputText type="text" styleClass="searchField"/>
+ <h:commandButton value="Search SeamSpace" onclick="javascript:alert('This feature coming soon!');return false" styleClass="searchButton"/>
+ </div>
+ </h:form>
+ </div>
+ </div>
+
+ <div id="menubar">
+ <s:link view="/home.xhtml" value="Home" propagation="none"/><h:outputText styleClass="divider" value=" | "/>
+ <s:link value="Browse" onclick="javascript:alert('This feature coming soon!');return false"/><h:outputText styleClass="divider" value=" | "/>
+ <s:link value="Blog" onclick="javascript:alert('This feature coming soon!');return false"/><h:outputText styleClass="divider" value=" | "/>
+ <s:link value="Music" onclick="javascript:alert('This feature coming soon!');return false"/>
+ </div>
+
+ <div id="content">
+ <ui:insert name="content"/>
+ </div>
+
+</body>
+</html>
+
Added: modules/security/trunk/examples/seamspace/src/main/webapp/userdetail.page.xml
===================================================================
--- modules/security/trunk/examples/seamspace/src/main/webapp/userdetail.page.xml (rev 0)
+++ modules/security/trunk/examples/seamspace/src/main/webapp/userdetail.page.xml 2010-03-25 02:33:21 UTC (rev 12264)
@@ -0,0 +1,9 @@
+<page xmlns="http://jboss.com/products/seam/pages"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://jboss.com/products/seam/pages http://jboss.com/products/seam/pages-2.2.xsd">
+ <navigation from-action="#{userAction.save}">
+ <rule if-outcome="success">
+ <redirect view-id="/usermanager.xhtml"/>
+ </rule>
+ </navigation>
+</page>
Added: modules/security/trunk/examples/seamspace/src/main/webapp/userdetail.xhtml
===================================================================
--- modules/security/trunk/examples/seamspace/src/main/webapp/userdetail.xhtml (rev 0)
+++ modules/security/trunk/examples/seamspace/src/main/webapp/userdetail.xhtml 2010-03-25 02:33:21 UTC (rev 12264)
@@ -0,0 +1,83 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:rich="http://richfaces.org/rich"
+ xmlns:s="http://jboss.com/products/seam/taglib">
+
+ <ui:composition template="template.xhtml">
+
+ <ui:define name="head">
+ <link href="style/security.css" rel="stylesheet" type="text/css"/>
+ </ui:define>
+
+ <ui:define name="content">
+
+ <div id="contentMain">
+
+ <h2>User Details</h2>
+
+ <h:messages globalOnly="true"/>
+
+ <h:form id="user">
+
+ <div class="formRow">
+ <h:outputLabel for="firstname" value="First name" styleClass="formLabel"/>
+ <h:inputText id="firstname" value="#{userAction.firstname}" readonly="#{identityManager.userExists(userAction.username)}"/>
+ <div class="validationError"><h:message for="firstname"/></div>
+ </div>
+
+ <div class="formRow">
+ <h:outputLabel for="lastname" value="Last name" styleClass="formLabel"/>
+ <h:inputText id="lastname" value="#{userAction.lastname}" readonly="#{identityManager.userExists(userAction.username)}"/>
+ <div class="validationError"><h:message for="lastname"/></div>
+ </div>
+
+ <div class="formRow">
+ <h:outputLabel for="username" value="Username" styleClass="formLabel"/>
+ <h:inputText id="username" value="#{userAction.username}" readonly="#{identityManager.userExists(userAction.username)}"/>
+ <div class="validationError"><h:message for="username"/></div>
+ </div>
+
+ <div class="formRow">
+ <h:outputLabel for="password" value="Password" styleClass="formLabel"/>
+ <h:inputSecret id="password" value="#{userAction.password}"/>
+ <div class="validationError"><h:message for="password"/></div>
+ </div>
+
+ <div class="formRow">
+ <h:outputLabel for="confirm" value="Confirm password" styleClass="formLabel"/>
+ <h:inputSecret id="confirm" value="#{userAction.confirm}"/>
+ </div>
+
+ <div class="formRow">
+ <h:outputLabel for="roles" value="Member of" styleClass="formLabel"/>
+ <div class="selectMany">
+ <h:selectManyCheckbox id="roles" value="#{userAction.roles}" layout="pageDirection" styleClass="roles">
+ <s:selectItems value="#{identityManager.listGrantableRoles()}" var="role" label="#{role}"/>
+ </h:selectManyCheckbox>
+ </div>
+ <div class="validationError"><h:message for="roles"/></div>
+ </div>
+
+ <div class="formRow">
+ <h:outputLabel for="enabled" value="Account enabled" styleClass="formLabel"/>
+ <h:selectBooleanCheckbox id="enabled" value="#{userAction.enabled}"/>
+ </div>
+
+ <div class="formButtons">
+ <h:commandButton id="save" value="Save" action="#{userAction.save}" styleClass="formButton"/>
+ <s:button id="cancel" view="/usermanager.xhtml" value="Cancel" propagation="end" styleClass="formButton"/>
+ </div>
+
+ <br class="clear"/>
+
+ </h:form>
+
+ </div>
+
+ </ui:define>
+
+ </ui:composition>
+</html>
Added: modules/security/trunk/examples/seamspace/src/main/webapp/usermanager.page.xml
===================================================================
--- modules/security/trunk/examples/seamspace/src/main/webapp/usermanager.page.xml (rev 0)
+++ modules/security/trunk/examples/seamspace/src/main/webapp/usermanager.page.xml 2010-03-25 02:33:21 UTC (rev 12264)
@@ -0,0 +1,14 @@
+<page xmlns="http://jboss.com/products/seam/pages"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://jboss.com/products/seam/pages http://jboss.com/products/seam/pages-2.2.xsd"
+ action="#{userSearch.loadUsers}">
+ <restrict>#{s:hasPermission('seam.user', 'read')}</restrict>
+
+ <navigation from-action="#{userAction.createUser}">
+ <redirect view-id="/userdetail.xhtml"/>
+ </navigation>
+
+ <navigation from-action="#{userAction.editUser(userSearch.selectedUser)}">
+ <redirect view-id="/userdetail.xhtml"/>
+ </navigation>
+</page>
Added: modules/security/trunk/examples/seamspace/src/main/webapp/usermanager.xhtml
===================================================================
--- modules/security/trunk/examples/seamspace/src/main/webapp/usermanager.xhtml (rev 0)
+++ modules/security/trunk/examples/seamspace/src/main/webapp/usermanager.xhtml 2010-03-25 02:33:21 UTC (rev 12264)
@@ -0,0 +1,74 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:s="http://jboss.com/products/seam/taglib">
+
+ <ui:composition template="template.xhtml">
+
+ <ui:define name="head">
+ <link href="style/security.css" rel="stylesheet" type="text/css"/>
+ </ui:define>
+
+ <ui:define name="content">
+
+ <script type="text/javascript">
+ function confirmDelete()
+ {
+ return confirm("Are you sure you wish to delete this user? This action cannot be undone.");
+ }
+ </script>
+
+ <div id="contentMain">
+
+ <h2>User Manager</h2>
+
+ <s:button id="newUser" action="#{userAction.createUser}" styleClass="newuser" rendered="#{s:hasPermission('seam.account', 'create')}"/>
+
+ <h:dataTable
+ id="threads"
+ value="#{users}"
+ var="user"
+ styleClass="security"
+ cellspacing="0"
+ headerClass="header"
+ rowClasses="odd,even"
+ columnClasses=",,enabled,action">
+ <h:column width="auto">
+ <f:facet name="header">
+ User name
+ </f:facet>
+ #{user}
+ </h:column>
+ <h:column width="auto">
+ <f:facet name="header">
+ Member Of
+ </f:facet>
+ #{userSearch.getUserRoles(user)}
+ </h:column>
+ <h:column id="enabled" width="auto">
+ <f:facet name="header">
+ Enabled
+ </f:facet>
+ <div class="#{identityManager.isUserEnabled(user) ? 'checkmark' : 'cross'}"/>
+ </h:column>
+ <h:column id="action" width="auto">
+ <f:facet name="header">
+ Action
+ </f:facet>
+
+ <s:fragment rendered="#{s:hasPermission('seam.user', 'update')}">
+ <s:link id="edit" value="Edit" action="#{userAction.editUser(userSearch.selectedUser)}"/><span> | </span>
+ </s:fragment>
+ <s:link id="delete" value="Delete" action="#{identityManager.deleteUser(userSearch.selectedUser)}"
+ rendered="#{s:hasPermission('seam.user', 'delete')}"
+ onclick="return confirmDelete()"/>
+ </h:column>
+ </h:dataTable>
+ </div>
+
+ </ui:define>
+
+ </ui:composition>
+</html>
Added: modules/security/trunk/examples/seamspace/src/main/webapp/welcome.xhtml
===================================================================
--- modules/security/trunk/examples/seamspace/src/main/webapp/welcome.xhtml (rev 0)
+++ modules/security/trunk/examples/seamspace/src/main/webapp/welcome.xhtml 2010-03-25 02:33:21 UTC (rev 12264)
@@ -0,0 +1,17 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:h="http://java.sun.com/jsf/html">
+
+<head>
+ <title>SeamSpace</title>
+</head>
+
+<body>
+ <h1>Login successful!</h1>
+
+ <div class="errors"><h:messages globalOnly="true"/></div>
+
+</body>
+</html>
+
14 years, 9 months
Seam SVN: r12263 - in modules/faces/trunk/src: main/java/org/jboss/seam/faces/context and 6 other directories.
by seam-commits@lists.jboss.org
Author: lincolnthree
Date: 2010-03-24 17:49:03 -0400 (Wed, 24 Mar 2010)
New Revision: 12263
Added:
modules/faces/trunk/src/main/java/org/jboss/seam/faces/context/conversation/
modules/faces/trunk/src/main/java/org/jboss/seam/faces/context/conversation/Begin.java
modules/faces/trunk/src/main/java/org/jboss/seam/faces/context/conversation/BeginConversationInterceptor.java
modules/faces/trunk/src/main/java/org/jboss/seam/faces/context/conversation/End.java
modules/faces/trunk/src/main/java/org/jboss/seam/faces/context/conversation/RetainsConversation.java
modules/faces/trunk/src/main/java/org/jboss/seam/faces/persistence/
modules/faces/trunk/src/main/java/org/jboss/seam/faces/persistence/TransactionManager.java
modules/faces/trunk/src/test/java/org/jboss/seam/faces/MockConversation.java
modules/faces/trunk/src/test/java/org/jboss/seam/faces/context/
modules/faces/trunk/src/test/java/org/jboss/seam/faces/context/conversation/
modules/faces/trunk/src/test/java/org/jboss/seam/faces/context/conversation/BeginConversationBean.java
modules/faces/trunk/src/test/java/org/jboss/seam/faces/context/conversation/BeginConversationInterceptorTest-beans.xml
modules/faces/trunk/src/test/java/org/jboss/seam/faces/context/conversation/BeginConversationInterceptorTest.java
Modified:
modules/faces/trunk/src/main/resources/META-INF/beans.xml
Log:
Started conversational support.
Added: modules/faces/trunk/src/main/java/org/jboss/seam/faces/context/conversation/Begin.java
===================================================================
--- modules/faces/trunk/src/main/java/org/jboss/seam/faces/context/conversation/Begin.java (rev 0)
+++ modules/faces/trunk/src/main/java/org/jboss/seam/faces/context/conversation/Begin.java 2010-03-24 21:49:03 UTC (rev 12263)
@@ -0,0 +1,34 @@
+package org.jboss.seam.faces.context.conversation;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import javax.enterprise.context.Conversation;
+import javax.interceptor.InterceptorBinding;
+
+/**
+ * Marks the beginning of a persistent {@link Conversation}.
+ *
+ *<p>
+ * <b>Note:</b> If this method throws an exception, the conversation will be
+ * discarded, unless the exception is annotated with @
+ * {@link RetainsConversation}
+ *
+ * @author <a href="mailto:lincolnbaxter@gmail.com">Lincoln Baxter, III</a>
+ */
+@InterceptorBinding
+@Target( { METHOD, TYPE })
+@Retention(RUNTIME)
+public @interface Begin
+{
+ /**
+ * The new conversation ID. Seam will Generate a conversation ID if left
+ * blank. If a conversation with the ID already exists, TODO what should we
+ * do?
+ */
+ String id() default "";
+}
\ No newline at end of file
Added: modules/faces/trunk/src/main/java/org/jboss/seam/faces/context/conversation/BeginConversationInterceptor.java
===================================================================
--- modules/faces/trunk/src/main/java/org/jboss/seam/faces/context/conversation/BeginConversationInterceptor.java (rev 0)
+++ modules/faces/trunk/src/main/java/org/jboss/seam/faces/context/conversation/BeginConversationInterceptor.java 2010-03-24 21:49:03 UTC (rev 12263)
@@ -0,0 +1,84 @@
+/**
+ *
+ */
+package org.jboss.seam.faces.context.conversation;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+
+import javax.enterprise.context.Conversation;
+import javax.inject.Inject;
+import javax.interceptor.AroundInvoke;
+import javax.interceptor.Interceptor;
+import javax.interceptor.InvocationContext;
+
+import org.slf4j.Logger;
+
+/**
+ * Intercepts methods annotated as Conversational entry points.
+ *
+ * @author <a href="mailto:lincolnbaxter@gmail.com">Lincoln Baxter, III</a>
+ *
+ */
+@Begin
+@Interceptor
+public class BeginConversationInterceptor
+{
+ @Inject
+ Logger log;
+
+ @Inject
+ Conversation conversation;
+
+ @AroundInvoke
+ public Object before(final InvocationContext ctx) throws Exception
+ {
+ String cid = getConversationId(ctx.getMethod());
+ if (cid != null)
+ {
+ conversation.begin(cid);
+ }
+ else
+ {
+ conversation.begin();
+ }
+
+ log.debug("Began conversation: (#0) on method: (#1.#2(...))", new Object[] { conversation.getId(), ctx.getMethod().getDeclaringClass().getName(), ctx.getMethod().getName() });
+
+ try
+ {
+ Object result = ctx.proceed();
+ return result;
+ }
+ catch (Exception e)
+ {
+ conversation.end();
+ throw e;
+ }
+
+ }
+
+ private String getConversationId(final Method m)
+ {
+ String result = null;
+ for (Annotation a : m.getAnnotations())
+ {
+ if (a.annotationType().isAnnotationPresent(Begin.class))
+ {
+ result = a.annotationType().getAnnotation(Begin.class).id();
+ }
+ }
+
+ if (result == null)
+ {
+ for (Annotation a : m.getDeclaringClass().getAnnotations())
+ {
+ if (a.annotationType().isAnnotationPresent(Begin.class))
+ {
+ result = a.annotationType().getAnnotation(Begin.class).id();
+ }
+ }
+ }
+ return result;
+ }
+}
Added: modules/faces/trunk/src/main/java/org/jboss/seam/faces/context/conversation/End.java
===================================================================
--- modules/faces/trunk/src/main/java/org/jboss/seam/faces/context/conversation/End.java (rev 0)
+++ modules/faces/trunk/src/main/java/org/jboss/seam/faces/context/conversation/End.java 2010-03-24 21:49:03 UTC (rev 12263)
@@ -0,0 +1,34 @@
+package org.jboss.seam.faces.context.conversation;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import javax.enterprise.context.Conversation;
+import javax.interceptor.InterceptorBinding;
+
+/**
+ * Marks the beginning of a persistent {@link Conversation}.
+ *
+ *<p>
+ * <b>Note:</b> If this method throws an exception, the conversation will be
+ * discarded, unless the exception is annotated with @
+ * {@link RetainsConversation}
+ *
+ * @author <a href="mailto:lincolnbaxter@gmail.com">Lincoln Baxter, III</a>
+ */
+@InterceptorBinding
+@Target( { METHOD, TYPE })
+@Retention(RUNTIME)
+public @interface End
+{
+ /**
+ * The new conversation ID. Seam will Generate a conversation ID if left
+ * blank. If a conversation with the ID already exists, TODO what should we
+ * do?
+ */
+ String id() default "";
+}
\ No newline at end of file
Added: modules/faces/trunk/src/main/java/org/jboss/seam/faces/context/conversation/RetainsConversation.java
===================================================================
--- modules/faces/trunk/src/main/java/org/jboss/seam/faces/context/conversation/RetainsConversation.java (rev 0)
+++ modules/faces/trunk/src/main/java/org/jboss/seam/faces/context/conversation/RetainsConversation.java 2010-03-24 21:49:03 UTC (rev 12263)
@@ -0,0 +1,35 @@
+package org.jboss.seam.faces.context.conversation;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import javax.enterprise.context.Conversation;
+import javax.inject.Qualifier;
+
+/**
+ * Marks the beginning of a persistent {@link Conversation}.
+ *
+ *<p>
+ * <b>Note:</b> If this method throws an exception, the conversation will be
+ * discarded, unless the exception is annotated with {@link RetainsConversation}
+ *
+ * @author <a href="mailto:lincolnbaxter@gmail.com">Lincoln Baxter, III</a>
+ */
+@Qualifier
+@Target( { FIELD, PARAMETER })
+@Retention(RUNTIME)
+@Documented
+public @interface RetainsConversation
+{
+ /**
+ * The new conversation ID. Seam will Generate a conversation ID if left
+ * blank. If a conversation with the ID already exists, TODO what should we
+ * do?
+ */
+ String id() default "";
+}
\ No newline at end of file
Added: modules/faces/trunk/src/main/java/org/jboss/seam/faces/persistence/TransactionManager.java
===================================================================
--- modules/faces/trunk/src/main/java/org/jboss/seam/faces/persistence/TransactionManager.java (rev 0)
+++ modules/faces/trunk/src/main/java/org/jboss/seam/faces/persistence/TransactionManager.java 2010-03-24 21:49:03 UTC (rev 12263)
@@ -0,0 +1,28 @@
+/**
+ *
+ */
+package org.jboss.seam.faces.persistence;
+
+import javax.enterprise.event.Observes;
+import javax.faces.event.PhaseEvent;
+
+import org.jboss.seam.faces.event.qualifier.Before;
+import org.jboss.seam.faces.event.qualifier.RenderResponse;
+import org.jboss.seam.faces.event.qualifier.RestoreView;
+
+/**
+ * @author <a href="mailto:lincolnbaxter@gmail.com">Lincoln Baxter, III</a>
+ *
+ */
+public class TransactionManager
+{
+
+ public void beginApplicationTransaction(@Observes @Before @RestoreView final PhaseEvent event)
+ {
+ }
+
+ public void endApplicationTransaction(@Observes @Before @RenderResponse final PhaseEvent event)
+ {
+ }
+
+}
Modified: modules/faces/trunk/src/main/resources/META-INF/beans.xml
===================================================================
--- modules/faces/trunk/src/main/resources/META-INF/beans.xml 2010-03-24 13:59:05 UTC (rev 12262)
+++ modules/faces/trunk/src/main/resources/META-INF/beans.xml 2010-03-24 21:49:03 UTC (rev 12263)
@@ -0,0 +1,10 @@
+<beans xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="
+ http://java.sun.com/xml/ns/javaee
+ http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
+
+ <interceptors>
+ <class>org.jboss.seam.faces.context.conversation.BeginConversationInterceptor</class>
+ </interceptors>
+
+</beans>
\ No newline at end of file
Added: modules/faces/trunk/src/test/java/org/jboss/seam/faces/MockConversation.java
===================================================================
--- modules/faces/trunk/src/test/java/org/jboss/seam/faces/MockConversation.java (rev 0)
+++ modules/faces/trunk/src/test/java/org/jboss/seam/faces/MockConversation.java 2010-03-24 21:49:03 UTC (rev 12263)
@@ -0,0 +1,60 @@
+/**
+ *
+ */
+package org.jboss.seam.faces;
+
+import javax.enterprise.context.Conversation;
+import javax.inject.Singleton;
+
+/**
+ * Provide a mocked conversation object for use in Unit tests. This entire class
+ * is a no-op; it does <i>nothing</i>.
+ *
+ * @author <a href="mailto:lincolnbaxter@gmail.com">Lincoln Baxter, III</a>
+ *
+ */
+@Singleton
+public class MockConversation implements Conversation
+{
+ private long timeout;
+ private String id;
+ private boolean persistent;
+
+ public void begin()
+ {
+ this.id = "generated";
+ persistent = true;
+ }
+
+ public void begin(final String id)
+ {
+ this.id = id;
+ persistent = true;
+ }
+
+ public void end()
+ {
+ persistent = false;
+ }
+
+ public String getId()
+ {
+ return id;
+ }
+
+ public long getTimeout()
+ {
+ return timeout;
+ }
+
+ public boolean isTransient()
+ {
+ return this.persistent == false;
+ }
+
+ public void setTimeout(final long milliseconds)
+ {
+ this.timeout = milliseconds;
+ }
+
+}
Added: modules/faces/trunk/src/test/java/org/jboss/seam/faces/context/conversation/BeginConversationBean.java
===================================================================
--- modules/faces/trunk/src/test/java/org/jboss/seam/faces/context/conversation/BeginConversationBean.java (rev 0)
+++ modules/faces/trunk/src/test/java/org/jboss/seam/faces/context/conversation/BeginConversationBean.java 2010-03-24 21:49:03 UTC (rev 12263)
@@ -0,0 +1,30 @@
+/**
+ *
+ */
+package org.jboss.seam.faces.context.conversation;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.context.Conversation;
+import javax.inject.Inject;
+
+/**
+ * @author <a href="mailto:lincolnbaxter@gmail.com">Lincoln Baxter, III</a>
+ *
+ */
+@ApplicationScoped
+public class BeginConversationBean
+{
+ @Inject
+ Conversation conversation;
+
+ public boolean conversationStarted = false;
+
+ @Begin
+ public void beginConversation()
+ {
+ if (conversation.isTransient() == false)
+ {
+ conversationStarted = true;
+ }
+ }
+}
Added: modules/faces/trunk/src/test/java/org/jboss/seam/faces/context/conversation/BeginConversationInterceptorTest-beans.xml
===================================================================
--- modules/faces/trunk/src/test/java/org/jboss/seam/faces/context/conversation/BeginConversationInterceptorTest-beans.xml (rev 0)
+++ modules/faces/trunk/src/test/java/org/jboss/seam/faces/context/conversation/BeginConversationInterceptorTest-beans.xml 2010-03-24 21:49:03 UTC (rev 12263)
@@ -0,0 +1,10 @@
+<beans xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="
+ http://java.sun.com/xml/ns/javaee
+ http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
+
+ <interceptors>
+ <class>org.jboss.seam.faces.context.conversation.BeginConversationInterceptor</class>
+ </interceptors>
+
+</beans>
\ No newline at end of file
Added: modules/faces/trunk/src/test/java/org/jboss/seam/faces/context/conversation/BeginConversationInterceptorTest.java
===================================================================
--- modules/faces/trunk/src/test/java/org/jboss/seam/faces/context/conversation/BeginConversationInterceptorTest.java (rev 0)
+++ modules/faces/trunk/src/test/java/org/jboss/seam/faces/context/conversation/BeginConversationInterceptorTest.java 2010-03-24 21:49:03 UTC (rev 12263)
@@ -0,0 +1,42 @@
+/**
+ *
+ */
+package org.jboss.seam.faces.context.conversation;
+
+import static org.junit.Assert.assertTrue;
+
+import javax.inject.Inject;
+
+import org.jboss.arquillian.api.Deployment;
+import org.jboss.seam.faces.MockConversation;
+import org.jboss.seam.faces.MockLogger;
+import org.jboss.shrinkwrap.api.ArchivePaths;
+import org.jboss.shrinkwrap.api.Archives;
+import org.jboss.shrinkwrap.api.spec.JavaArchive;
+import org.junit.experimental.categories.Category;
+import org.junit.internal.runners.statements.Fail;
+
+/**
+ * @author <a href="mailto:lincolnbaxter@gmail.com">Lincoln Baxter, III</a>
+ *
+ */
+// @RunWith(Arquillian.class)
+public class BeginConversationInterceptorTest
+{
+ @Deployment
+ public static JavaArchive createTestArchive()
+ {
+ return Archives.create("test.jar", JavaArchive.class).addClasses(BeginConversationInterceptor.class, BeginConversationBean.class, MockLogger.class, MockConversation.class).addManifestResource(BeginConversationInterceptorTest.class.getPackage().getName().replaceAll("\\.", "/") + "/BeginConversationInterceptorTest-beans.xml", ArchivePaths.create("beans.xml"));
+ }
+
+ @Inject
+ private BeginConversationBean bean;
+
+ // @Test
+ @Category(Fail.class)
+ public void testConversationStarted()
+ {
+ bean.beginConversation();
+ assertTrue(bean.conversationStarted);
+ }
+}
14 years, 9 months
Seam SVN: r12262 - in branches/enterprise/JBPAPP_4_2_CP01: src/main/org/jboss/seam/mock and 1 other directory.
by seam-commits@lists.jboss.org
Author: manaRH
Date: 2010-03-24 09:59:05 -0400 (Wed, 24 Mar 2010)
New Revision: 12262
Modified:
branches/enterprise/JBPAPP_4_2_CP01/examples/blog/src/test/BlogTest.java
branches/enterprise/JBPAPP_4_2_CP01/src/main/org/jboss/seam/mock/MockStateManager.java
branches/enterprise/JBPAPP_4_2_CP01/src/main/org/jboss/seam/mock/SeamTest.java
Log:
JBPAPP-3138 - fixing Blog example test
Modified: branches/enterprise/JBPAPP_4_2_CP01/examples/blog/src/test/BlogTest.java
===================================================================
--- branches/enterprise/JBPAPP_4_2_CP01/examples/blog/src/test/BlogTest.java 2010-03-24 12:36:35 UTC (rev 12261)
+++ branches/enterprise/JBPAPP_4_2_CP01/examples/blog/src/test/BlogTest.java 2010-03-24 13:59:05 UTC (rev 12262)
@@ -8,6 +8,7 @@
import org.jboss.seam.jsf.SeamPhaseListener;
import org.jboss.seam.jsf.TransactionalSeamPhaseListener;
import org.jboss.seam.mock.SeamTest;
+import org.jboss.seam.security.Identity;
import org.testng.annotations.Test;
import actions.BlogService;
@@ -21,6 +22,20 @@
@Test
public void testPost() throws Exception
{
+ new FacesRequest()
+ {
+ @Override
+ protected void updateModelValues() throws Exception
+ {
+ Identity.instance().setPassword("tokyo");
+ }
+ @Override
+ protected void invokeApplication() throws Exception
+ {
+ Identity.instance().authenticate();
+ }
+ }.run();
+
new FacesRequest("/post.xhtml")
{
Modified: branches/enterprise/JBPAPP_4_2_CP01/src/main/org/jboss/seam/mock/MockStateManager.java
===================================================================
--- branches/enterprise/JBPAPP_4_2_CP01/src/main/org/jboss/seam/mock/MockStateManager.java 2010-03-24 12:36:35 UTC (rev 12261)
+++ branches/enterprise/JBPAPP_4_2_CP01/src/main/org/jboss/seam/mock/MockStateManager.java 2010-03-24 13:59:05 UTC (rev 12262)
@@ -8,7 +8,16 @@
public class MockStateManager extends StateManager {
+
@Override
+ public void writeState(FacesContext ctx, Object state) throws IOException {}
+
+ @Override
+ public Object saveView(FacesContext ctx) {
+ return null;
+ }
+
+ @Override
public SerializedView saveSerializedView(FacesContext ctx) {
return null;
}
Modified: branches/enterprise/JBPAPP_4_2_CP01/src/main/org/jboss/seam/mock/SeamTest.java
===================================================================
--- branches/enterprise/JBPAPP_4_2_CP01/src/main/org/jboss/seam/mock/SeamTest.java 2010-03-24 12:36:35 UTC (rev 12261)
+++ branches/enterprise/JBPAPP_4_2_CP01/src/main/org/jboss/seam/mock/SeamTest.java 2010-03-24 13:59:05 UTC (rev 12262)
@@ -1,9 +1,9 @@
/*
-�* JBoss, Home of Professional Open Source
-�*
-�* Distributable under LGPL license.
-�* See terms of license at gnu.org.
-�*/
+�* JBoss, Home of Professional Open Source
+�*
+�* Distributable under LGPL license.
+�* See terms of license at gnu.org.
+�*/
package org.jboss.seam.mock;
import java.lang.reflect.Field;
@@ -415,6 +415,16 @@
beforeRequest();
+// Map<String, String> params = new HashMap<String, String>();
+// for (Map.Entry<String, String[]> e: ( (Map<String, String[]>) request.getParameterMap() ).entrySet())
+// {
+// if ( e.getValue().length==1 )
+// {
+// params.put( e.getKey(), e.getValue()[0] );
+// }
+// }
+// request.setAttribute("param", params);
+
phases.beforePhase( new PhaseEvent(facesContext, PhaseId.RESTORE_VIEW, MockLifecycle.INSTANCE) );
UIViewRoot viewRoot = facesContext.getApplication().getViewHandler().createView( facesContext, getViewId() );
@@ -437,8 +447,12 @@
}
}
}
- if ( !isGetRequest() )
+ if ( isGetRequest() )
{
+ facesContext.renderResponse();
+ }
+ else
+ {
restoredViewRootAttributes.putAll(pageParameters);
}
14 years, 9 months
Seam SVN: r12261 - in branches/community/Seam_2_2/src/test/ftest: examples and 6 other directories.
by seam-commits@lists.jboss.org
Author: kpiwko(a)redhat.com
Date: 2010-03-24 08:36:35 -0400 (Wed, 24 Mar 2010)
New Revision: 12261
Added:
branches/community/Seam_2_2/src/test/ftest/examples/seambay/jboss5-webdriver.xml
branches/community/Seam_2_2/src/test/ftest/examples/seambay/src/org/jboss/seam/example/seambay/test/webdriver/
branches/community/Seam_2_2/src/test/ftest/examples/seambay/src/org/jboss/seam/example/seambay/test/webdriver/seambay/
branches/community/Seam_2_2/src/test/ftest/examples/seambay/src/org/jboss/seam/example/seambay/test/webdriver/seambay/WebServicesTest.java
branches/community/Seam_2_2/src/test/ftest/src/main/org/jboss/seam/example/common/test/webdriver/
branches/community/Seam_2_2/src/test/ftest/src/main/org/jboss/seam/example/common/test/webdriver/AjaxWebDriver.java
branches/community/Seam_2_2/src/test/ftest/src/main/org/jboss/seam/example/common/test/webdriver/AjaxWebDriverFactory.java
branches/community/Seam_2_2/src/test/ftest/src/main/org/jboss/seam/example/common/test/webdriver/AjaxWebDriverTest.java
branches/community/Seam_2_2/src/test/ftest/src/main/org/jboss/seam/example/common/test/webdriver/AjaxWebElement.java
branches/community/Seam_2_2/src/test/ftest/src/main/org/jboss/seam/example/common/test/webdriver/DelegatedWebElement.java
branches/community/Seam_2_2/src/test/ftest/src/main/org/jboss/seam/example/common/test/webdriver/FirefoxAjaxDriver.java
Modified:
branches/community/Seam_2_2/src/test/ftest/build.xml
branches/community/Seam_2_2/src/test/ftest/examples/build.xml
branches/community/Seam_2_2/src/test/ftest/examples/seambay/jboss5.xml
Log:
JBSEAM-4610, WebDriver infrastructure + SeamBay webservices test
Modified: branches/community/Seam_2_2/src/test/ftest/build.xml
===================================================================
--- branches/community/Seam_2_2/src/test/ftest/build.xml 2010-03-24 11:27:19 UTC (rev 12260)
+++ branches/community/Seam_2_2/src/test/ftest/build.xml 2010-03-24 12:36:35 UTC (rev 12261)
@@ -78,7 +78,7 @@
<testexample name="registration" />
<testexample name="remoting/chatroom" />
<testexample name="rss" />
- <testexample name="seambay" />
+ <testexample name="seambay" webdriver="true"/>
<testexample name="seamdiscs" />
<testexample name="seampay" />
<testexample name="seamspace" />
@@ -123,8 +123,8 @@
<testexample name="remoting/chatroom" />
<testexample name="remoting/helloworld" />
<testexample name="remoting/gwt" />
- <testexample name="rss" />
- <testexample name="seambay" />
+ <testexample name="rss" />
+ <testexample name="seambay" webdriver="true"/>
<testexample name="seampay" />
<testexample name="seamspace" />
<testexample name="spring" />
@@ -132,7 +132,7 @@
<testexample name="todo" />
<testexample name="ui" />
<testexample name="wicket" />
- <testexample name="wicket-runtime" />
+ <testexample name="wicket-runtime" />
<antcall target="stop.selenium.server" />
<antcall target="stop.container" />
</target>
@@ -146,7 +146,7 @@
<testexample name="messages" />
<testexample name="numberguess" />
<testexample name="registration" />
- <testexample name="seambay" />
+ <testexample name="seambay" webdriver="true"/>
<testexample name="seampay" />
<testexample name="todo" />
<testexample name="booking" />
@@ -195,7 +195,7 @@
<antcall target="start.selenium.server" />
<!-- Execute tests for a specific example-->
- <testexample name="${test}" />
+ <testexample name="${test}" webdriver="${webdriver}" />
<antcall target="stop.selenium.server" />
</target>
@@ -311,6 +311,7 @@
<macrodef name="testexample">
<attribute name="name" />
<attribute name="path" default="examples/@{name}" />
+ <attribute name="webdriver" default="false" />
<attribute name="message" default="Running functional tests on @{name} example" />
<sequential>
<groovy>
@@ -325,7 +326,7 @@
]]>
</groovy>
<echo>@{message}</echo>
- <callExample path="@{path}" target="test" />
+ <callExample path="@{path}" target="test" webdriver="@{webdriver}"/>
</sequential>
</macrodef>
@@ -350,10 +351,11 @@
<macrodef name="callExample">
<attribute name="path" />
<attribute name="target" />
+ <attribute name="webdriver" default="false"/>
<sequential>
<ant dir="@{path}" target="@{target}" inheritall="false">
- <property name="container" value="${container}">
- </property>
+ <property name="container" value="${container}" />
+ <property name="webdriver" value="@{webdriver}" />
</ant>
</sequential>
</macrodef>
Modified: branches/community/Seam_2_2/src/test/ftest/examples/build.xml
===================================================================
--- branches/community/Seam_2_2/src/test/ftest/examples/build.xml 2010-03-24 11:27:19 UTC (rev 12260)
+++ branches/community/Seam_2_2/src/test/ftest/examples/build.xml 2010-03-24 12:36:35 UTC (rev 12261)
@@ -101,7 +101,7 @@
<!-- TODO we should compile this once to a common place not build for each example -->
<!-- TODO if needed we should allow examples to exclude/include src under
common dvd does not care about booking for example-->
- <target name="build.common" depends="copy.htmlunit, copy.selenium" description="Compiles the common selenium test code">
+ <target name="build.common" depends="copy.htmlunit, copy.selenium, copy.webdriver" description="Compiles the common selenium test code">
<mkdir dir="${classes.dir}" />
<javac srcdir="${common.src.dir}" destdir="${classes.dir}" classpathref="classpath.build" debug="true" />
<copy todir="${classes.dir}">
@@ -141,6 +141,27 @@
</testng>
</target>
+ <target name="webdriver.test" depends="webdriver.test.present, build, container.properties" description="Run Tests (WebDriver)" if="test.webdriver">
+ <taskdef resource="testngtasks" classpathref="classpath.test" />
+ <mkdir dir="${test.output.dir}" />
+ <echo message="${test.webdriver}" />
+ <!-- execute testng tests -->
+ <testng haltonfailure="false" outputdir="${test.output.dir}" classpathref="classpath.test">
+ <xmlfileset file="${container}-webdriver.xml" />
+ <sysproperty key="browser" value="${selenium.browser}" />
+ <sysproperty key="server.url" value="${selenium.browser.url}" />
+ <sysproperty key="context.path" value="${context.path}" />
+ </testng>
+ </target>
+
+ <target name="webdriver.test.present">
+ <condition property="test.webdriver">
+ <not>
+ <equals arg1="${webdriver}" arg2="false"/>
+ </not>
+ </condition>
+ </target>
+
<target name="simpletest" depends="build, container.properties" description="Run Tests" unless="cluster">
<!-- TODO all of these jboss commands must be optional with checks -->
<!-- TODO go get JBoss and extract -->
@@ -154,6 +175,7 @@
<!-- execute testng tests -->
<antcall target="selenium.test" />
+ <antcall target="webdriver.test"/>
<!-- undeploy the example -->
<antcall target="undeploy.example" />
@@ -356,4 +378,14 @@
<property name="copy.selenium.done" value="true" />
</target>
+ <target name="copy.webdriver" unless="copy.webdriver.done">
+ <copyInlineDependencies id="webdriver.driver" scope="compile" todir="${ftest.lib.dir}">
+ <dependency groupId="org.seleniumhq.webdriver" artifactId="webdriver-firefox" version="0.9.7376">
+ </dependency>
+ <dependency groupId="org.seleniumhq.webdriver" artifactId="webdriver-support" version="0.9.7376">
+ </dependency>
+ </copyInlineDependencies>
+ <property name="copy.webdriver.done" value="true" />
+ </target>
+
</project>
Added: branches/community/Seam_2_2/src/test/ftest/examples/seambay/jboss5-webdriver.xml
===================================================================
--- branches/community/Seam_2_2/src/test/ftest/examples/seambay/jboss5-webdriver.xml (rev 0)
+++ branches/community/Seam_2_2/src/test/ftest/examples/seambay/jboss5-webdriver.xml 2010-03-24 12:36:35 UTC (rev 12261)
@@ -0,0 +1,25 @@
+
+ <!--
+ JBoss, Home of Professional Open Source Copyright 2008, Red Hat
+ Middleware LLC, and individual contributors by the @authors tag. See
+ the copyright.txt in the distribution for a full listing of individual
+ contributors. This is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 of the
+ License, or (at your option) any later version. This software is
+ distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details. You should have received a copy of the GNU
+ Lesser General Public License along with this software; if not, write
+ to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ Boston, MA 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ -->
+<!DOCTYPE suite SYSTEM "http://beust.com/testng/testng-1.0.dtd" >
+<suite name="Web Driver Seambay example" verbose="2" parallel="false">
+ <test name="seambay_jboss5_webdriver">
+ <packages>
+ <package name="org.jboss.seam.example.test.webdriver.seambay" />
+ </packages>
+ </test>
+</suite>
Modified: branches/community/Seam_2_2/src/test/ftest/examples/seambay/jboss5.xml
===================================================================
--- branches/community/Seam_2_2/src/test/ftest/examples/seambay/jboss5.xml 2010-03-24 11:27:19 UTC (rev 12260)
+++ branches/community/Seam_2_2/src/test/ftest/examples/seambay/jboss5.xml 2010-03-24 12:36:35 UTC (rev 12261)
@@ -20,13 +20,14 @@
<test name="seambay_jboss5">
<parameter name="PROPERTY_FILE"
value="/org/jboss/seam/example/seambay/test/selenium/seambay.properties" />
- <classes>
+ <classes>
<class
name="org.jboss.seam.example.seambay.test.selenium.RegistrationTest" />
<class name="org.jboss.seam.example.seambay.test.selenium.SellTest" />
<class name="org.jboss.seam.example.seambay.test.selenium.SearchTest" />
- <class name="org.jboss.seam.example.seambay.test.selenium.BidTest" />
+ <class name="org.jboss.seam.example.seambay.test.selenium.BidTest" /> <!--
<class name="org.jboss.seam.example.seambay.test.selenium.WebServiceTestPageTest" />
+ -->
</classes>
</test>
</suite>
Added: branches/community/Seam_2_2/src/test/ftest/examples/seambay/src/org/jboss/seam/example/seambay/test/webdriver/seambay/WebServicesTest.java
===================================================================
--- branches/community/Seam_2_2/src/test/ftest/examples/seambay/src/org/jboss/seam/example/seambay/test/webdriver/seambay/WebServicesTest.java (rev 0)
+++ branches/community/Seam_2_2/src/test/ftest/examples/seambay/src/org/jboss/seam/example/seambay/test/webdriver/seambay/WebServicesTest.java 2010-03-24 12:36:35 UTC (rev 12261)
@@ -0,0 +1,265 @@
+package org.jboss.seam.example.test.webdriver.seambay;
+
+import static junit.framework.Assert.assertTrue;
+
+import org.jboss.seam.example.common.test.webdriver.AjaxWebDriverTest;
+import org.jboss.seam.example.common.test.webdriver.AjaxWebElement;
+import org.openqa.selenium.By;
+import org.testng.annotations.Test;
+
+/**
+ * Tests Web Services of Seambay example. Uses WebDriver to test, browser is
+ * chosen according to parameter passed
+ *
+ * @author kpiwko
+ *
+ */
+public class WebServicesTest extends AjaxWebDriverTest
+{
+
+ protected static final By HERE_LINK = By.partialLinkText("here");
+ protected static final String SERVICE_PAGE_URL = "test.seam";
+
+ protected static final By INVOKE_SERVICE_BUTTON = By.xpath("//button[contains(@onclick,'sendRequest')]");
+ protected static final By REQUEST_AREA = By.id("serviceRequest");
+ protected static final By RESPONSE_AREA = By.id("serviceResponse");
+
+ protected static final By LOGIN_LINK = By.partialLinkText("Login");
+ protected static final By LIST_CATEGORIES_LINK = By.partialLinkText("List Categories");
+ protected static final By CREATE_NEW_AUCTION_LINK = By.partialLinkText("Create new auction");
+ protected static final By UPDATE_AUCTION_DETAILS_LINK = By.partialLinkText("Update auction details");
+ protected static final By SET_AUCTION_DURATION_LINK = By.partialLinkText("Set auction duration");
+ protected static final By SET_STARTING_PRICE_LINK = By.partialLinkText("Set starting price");
+ protected static final By GET_AUCTION_DETAILS_LINK = By.partialLinkText("Get the auction details");
+ protected static final By CONFIRM_AUCTION_LINK = By.partialLinkText("Confirm auction");
+ protected static final By FIND_AUCTIONS_LINK = By.partialLinkText("Find Auctions");
+ protected static final By LOGOUT_LINK = By.partialLinkText("Logout");
+
+ /* login parameters */
+ protected static final By LOGIN_INPUT_USERNAME = By.id("username");
+ protected static final By LOGIN_INPUT_PASSWORD = By.id("password");
+
+ /* create new auction parameters */
+ protected static final By AUCTION_TITLE = By.id("title");
+ protected static final By AUCTION_DESCRIPTION = By.id("description");
+ protected static final By AUCTION_CATEGORY_ID = By.id("categoryId");
+
+ /* parameters for other tests */
+ protected static final By SEARCH_TERM = By.id("searchTerm");
+ protected static final By AUCTION_DURATION = By.id("duration");
+ protected static final By STARTING_PRICE = By.id("price");
+
+ /* responses */
+ protected static final String LIST_CATEGORIES_RESPONSE = "<ns2:listCategoriesResponse xmlns:ns2=\"http://seambay.example.seam.jboss.org/\"><return><categoryId>1</categoryId><name>Antiques</name></return><return><categoryId>2</categoryId><name>Art</name></return><return><categoryId>3</categoryId><name>Books</name></return><return><categoryId>4</categoryId><name>Cameras and Photography</name></return><return><categoryId>5</categoryId><name>Cars and Boats</name></return><return><categoryId>6</categoryId><name>Cell Phones</name></return><return><categoryId>7</categoryId><name>Clothing and Shoes</name></return><return><categoryId>8</categoryId><name>Computers</name></return><return><categoryId>9</categoryId><name>Music</name></return><return><categoryId>10</categoryId><name>Electronics</name></return><return><categoryId>11</categoryId><name>Home and Garden</name></return><return><categoryId>12</categoryId><name>Musical Instruments</name></return><return><categoryId>13</catego!
ryId><name>Sporting goods</name></return><return><categoryId>14</categoryId><name>Toys</name></return><return><categoryId>15</categoryId><name>Video Games</name></return><return><categoryId>1001</categoryId><name>Furniture</name><parent><categoryId>1</categoryId><name>Antiques</name></parent></return><return><categoryId>1002</categoryId><name>Silverware</name><parent><categoryId>1</categoryId><name>Antiques</name></parent></return><return><categoryId>2001</categoryId><name>Paintings</name><parent><categoryId>2</categoryId><name>Art</name></parent></return><return><categoryId>2002</categoryId><name>Prints</name><parent><categoryId>2</categoryId><name>Art</name></parent></return><return><categoryId>2003</categoryId><name>Sculptures</name><parent><categoryId>2</categoryId><name>Art</name></parent></return><return><categoryId>3001</categoryId><name>Fiction</name><parent><categoryId>3</categoryId><name>Books</name></parent></return><return><categoryId>3002</categoryId><name>Non !
Fiction</name><parent><categoryId>3</categoryId><name>Books</n!
ame></pa
rent></return><return><categoryId>3003</categoryId><name>Comic Books</name><parent><categoryId>3</categoryId><name>Books</name></parent></return><return><categoryId>3004</categoryId><name>Children</name><parent><categoryId>3</categoryId><name>Books</name></parent></return><return><categoryId>4001</categoryId><name>Digital Cameras</name><parent><categoryId>4</categoryId><name>Cameras and Photography</name></parent></return><return><categoryId>4002</categoryId><name>Memory Cards</name><parent><categoryId>4</categoryId><name>Cameras and Photography</name></parent></return><return><categoryId>4003</categoryId><name>Film Cameras</name><parent><categoryId>4</categoryId><name>Cameras and Photography</name></parent></return><return><categoryId>4004</categoryId><name>Video Cameras</name><parent><categoryId>4</categoryId><name>Cameras and Photography</name></parent></return><return><categoryId>5001</categoryId><name>Cars</name><parent><categoryId>5</categoryId><name>Cars and Boats</na!
me></parent></return><return><categoryId>5002</categoryId><name>Motorcycles</name><parent><categoryId>5</categoryId><name>Cars and Boats</name></parent></return><return><categoryId>5003</categoryId><name>Car Parts</name><parent><categoryId>5</categoryId><name>Cars and Boats</name></parent></return><return><categoryId>6001</categoryId><name>Mobile Phones</name><parent><categoryId>6</categoryId><name>Cell Phones</name></parent></return><return><categoryId>6002</categoryId><name>Mobile Accessories</name><parent><categoryId>6</categoryId><name>Cell Phones</name></parent></return><return><categoryId>6003</categoryId><name>Prepaid cards</name><parent><categoryId>6</categoryId><name>Cell Phones</name></parent></return><return><categoryId>7001</categoryId><name>Women</name><parent><categoryId>7</categoryId><name>Clothing and Shoes</name></parent></return><return><categoryId>7002</categoryId><name>Men</name><parent><categoryId>7</categoryId><name>Clothing and Shoes</name></parent></!
return><return><categoryId>7003</categoryId><name>Girls</name>!
<parent>
<categoryId>7</categoryId><name>Clothing and Shoes</name></parent></return><return><categoryId>7004</categoryId><name>Boys</name><parent><categoryId>7</categoryId><name>Clothing and Shoes</name></parent></return><return><categoryId>7005</categoryId><name>Babies</name><parent><categoryId>7</categoryId><name>Clothing and Shoes</name></parent></return><return><categoryId>8001</categoryId><name>Notebooks</name><parent><categoryId>8</categoryId><name>Computers</name></parent></return><return><categoryId>8002</categoryId><name>Desktop PCs</name><parent><categoryId>8</categoryId><name>Computers</name></parent></return><return><categoryId>8003</categoryId><name>Servers</name><parent><categoryId>8</categoryId><name>Computers</name></parent></return><return><categoryId>8004</categoryId><name>Hardware</name><parent><categoryId>8</categoryId><name>Computers</name></parent></return><return><categoryId>8005</categoryId><name>Software</name><parent><categoryId>8</categoryId><name>Computers!
</name></parent></return><return><categoryId>9001</categoryId><name>CDs</name><parent><categoryId>9</categoryId><name>Music</name></parent></return><return><categoryId>9002</categoryId><name>Records</name><parent><categoryId>9</categoryId><name>Music</name></parent></return><return><categoryId>10001</categoryId><name>Home Audio</name><parent><categoryId>10</categoryId><name>Electronics</name></parent></return><return><categoryId>10002</categoryId><name>MP3 Players</name><parent><categoryId>10</categoryId><name>Electronics</name></parent></return><return><categoryId>10003</categoryId><name>Television</name><parent><categoryId>10</categoryId><name>Electronics</name></parent></return><return><categoryId>10004</categoryId><name>Home theatre</name><parent><categoryId>10</categoryId><name>Electronics</name></parent></return><return><categoryId>11001</categoryId><name>Kitchen</name><parent><categoryId>11</categoryId><name>Home and Garden</name></parent></return><return><categoryId!
>11002</categoryId><name>Real Estate</name><parent><categoryId!
>11</cat
egoryId><name>Home and Garden</name></parent></return><return><categoryId>11003</categoryId><name>Furniture</name><parent><categoryId>11</categoryId><name>Home and Garden</name></parent></return><return><categoryId>12001</categoryId><name>Guitars</name><parent><categoryId>12</categoryId><name>Musical Instruments</name></parent></return><return><categoryId>12002</categoryId><name>Pianos and Keyboards</name><parent><categoryId>12</categoryId><name>Musical Instruments</name></parent></return><return><categoryId>12003</categoryId><name>Percussion</name><parent><categoryId>12</categoryId><name>Musical Instruments</name></parent></return><return><categoryId>12004</categoryId><name>Orchestral</name><parent><categoryId>12</categoryId><name>Musical Instruments</name></parent></return><return><categoryId>13001</categoryId><name>Golf</name><parent><categoryId>13</categoryId><name>Sporting goods</name></parent></return><return><categoryId>13002</categoryId><name>Fishing</name><parent><c!
ategoryId>13</categoryId><name>Sporting goods</name></parent></return><return><categoryId>13003</categoryId><name>Tennis</name><parent><categoryId>13</categoryId><name>Sporting goods</name></parent></return><return><categoryId>14001</categoryId><name>Remote control</name><parent><categoryId>14</categoryId><name>Toys</name></parent></return><return><categoryId>14002</categoryId><name>Cars and trucks</name><parent><categoryId>14</categoryId><name>Toys</name></parent></return><return><categoryId>14003</categoryId><name>Dolls</name><parent><categoryId>14</categoryId><name>Toys</name></parent></return><return><categoryId>14004</categoryId><name>Educational</name><parent><categoryId>14</categoryId><name>Toys</name></parent></return><return><categoryId>15001</categoryId><name>PC</name><parent><categoryId>15</categoryId><name>Video Games</name></parent></return><return><categoryId>15002</categoryId><name>Nintendo Wii</name><parent><categoryId>15</categoryId><name>Video Games</name>!
</parent></return><return><categoryId>15003</categoryId><name>!
Sony Pla
ystation 3</name><parent><categoryId>15</categoryId><name>Video Games</name></parent></return><return><categoryId>15004</categoryId><name>XBox 360</name><parent><categoryId>15</categoryId><name>Video Games</name></parent></return></ns2:listCategoriesResponse>";
+ protected static final String LOGIN_RIGHT_RESPONSE = "<return>true</return>";
+ protected static final String CREATE_NEW_AUCTION_RESPONSE = "<ns2:createAuctionResponse xmlns:ns2=\"http://seambay.example.seam.jboss.org/\"/>";
+ protected static final String FIND_AUCTIONS_RESPONSE = "<description>You can buy an animal here</description>";
+ protected static final String UPDATE_AUCTION_RESPONSE = "<ns2:updateAuctionDetailsResponse xmlns:ns2=\"http://seambay.example.seam.jboss.org/\"/>";
+ protected static final String SET_DURATION_RESPONSE = "<ns2:setAuctionDurationResponse xmlns:ns2=\"http://seambay.example.seam.jboss.org/\"/>";
+ protected static final String SET_STARTING_PRICE_RESPONSE = "<ns2:setAuctionPriceResponse xmlns:ns2=\"http://seambay.example.seam.jboss.org/\"/>";
+ protected static final String AUCTION_DETAILS_PRICE_RESPONSE = "<ns2:getNewAuctionDetailsResponse xmlns:ns2=\"http://seambay.example.seam.jboss.org/\"><return><account><accountId>1</accountId><feedbackPercent>0.0</feedbackPercent><feedbackScore>0</feedbackScore><location>Sydney, NSW, Australia</location>";
+ protected static final String LOGOUT_RESPONSE = "<ns2:logoutResponse xmlns:ns2=\"http://seambay.example.seam.jboss.org/\"><return>true</return></ns2:logoutResponse>";
+ protected static final String CONFIRMATION_RESPONSE = "<env:Body><ns2:confirmAuctionResponse xmlns:ns2=\"http://seambay.example.seam.jboss.org/\"/></env:Body>";
+
+ @Test
+ public void testGoToWSPage()
+ {
+ driver.get(serverURL + contextPath);
+ driver.findElement(HERE_LINK).click();
+
+ assertTrue("URL contains web services page", driver.getCurrentUrl().contains(SERVICE_PAGE_URL));
+ }
+
+ @Test(dependsOnMethods = {
+ "testGoToWSPage"
+ })
+ public void testLoginService()
+ {
+ loginService();
+ AjaxWebElement response = driver.findElement(RESPONSE_AREA);
+
+ // the same as Selenium, must use getValue to retrieve text inside
+ // <textarea></textarea>
+ assertTrue("Response area should contain \"true\"", response.getValue().contains(LOGIN_RIGHT_RESPONSE));
+ }
+
+ @Test(dependsOnMethods = {
+ "testLoginService"
+ })
+ public void listCategoriesTest()
+ {
+ loginService();
+ driver.findElement(LIST_CATEGORIES_LINK).clickAndWait();
+ driver.findElement(INVOKE_SERVICE_BUTTON).clickAndWait();
+
+ AjaxWebElement response = driver.findElement(RESPONSE_AREA);
+
+ assertTrue("Response area should contain a list of categories.", response.getValue().contains(LIST_CATEGORIES_RESPONSE));
+ }
+
+ @Test(dependsOnMethods = {
+ "testLoginService"
+ })
+ public void testCreateNewAuction()
+ {
+ loginService();
+ createNewAuctionService();
+ AjaxWebElement response = driver.findElement(RESPONSE_AREA);
+
+ assertTrue("Response area should contain information about creating the auction.", response.getValue().contains(CREATE_NEW_AUCTION_RESPONSE));
+ }
+
+ @Test(dependsOnMethods = {
+ "testLoginService", "testCreateNewAuction"
+ })
+ public void findAuctionsTest()
+ {
+ String searchTerm = "Animals";
+ loginService();
+ createNewAuctionService();
+ confirmAuctionService();
+ driver.findElement(FIND_AUCTIONS_LINK).clickAndWait();
+ driver.findElement(SEARCH_TERM).clearAndSendKeys(searchTerm);
+ driver.findElement(INVOKE_SERVICE_BUTTON).clickAndWait();
+
+ AjaxWebElement response = driver.findElement(RESPONSE_AREA);
+
+ assertTrue("Response area should contain information about finding auction.", response.getValue().contains(FIND_AUCTIONS_RESPONSE));
+ }
+
+ @Test(dependsOnMethods = {
+ "testLoginService", "testCreateNewAuction"
+ })
+ public void updateAuctionTest()
+ {
+ String title = "Animals";
+ String description = "Another description";
+ String categoryId = "5";
+ loginService();
+ createNewAuctionService();
+
+ driver.findElement(UPDATE_AUCTION_DETAILS_LINK).clickAndWait();
+ driver.findElement(AUCTION_TITLE).clearAndSendKeys(title);
+ driver.findElement(AUCTION_DESCRIPTION).clearAndSendKeys(description);
+ driver.findElement(AUCTION_CATEGORY_ID).clearAndSendKeys(categoryId);
+ driver.findElement(INVOKE_SERVICE_BUTTON).clickAndWait();
+
+ AjaxWebElement response = driver.findElement(RESPONSE_AREA);
+
+ assertTrue("Response area should contain information about updating the auction.", response.getValue().contains(UPDATE_AUCTION_RESPONSE));
+ }
+
+ @Test(dependsOnMethods = {
+ "testLoginService", "testCreateNewAuction"
+ })
+ public void setAuctionDurationTest()
+ {
+ String duration = "20";
+ loginService();
+ createNewAuctionService();
+
+ driver.findElement(SET_AUCTION_DURATION_LINK).clickAndWait();
+ driver.findElement(AUCTION_DURATION).clearAndSendKeys(duration);
+ driver.findElement(INVOKE_SERVICE_BUTTON).clickAndWait();
+
+ AjaxWebElement response = driver.findElement(RESPONSE_AREA);
+ assertTrue("Response area should contain information about setting duration.", response.getValue().contains(SET_DURATION_RESPONSE));
+ }
+
+ @Test(dependsOnMethods = {
+ "testLoginService", "testCreateNewAuction"
+ })
+ public void setStartingPriceTest()
+ {
+ String price = "1000";
+ loginService();
+ createNewAuctionService();
+
+ driver.findElement(SET_STARTING_PRICE_LINK).clickAndWait();
+ driver.findElement(STARTING_PRICE).clearAndSendKeys(price);
+ driver.findElement(INVOKE_SERVICE_BUTTON).clickAndWait();
+
+ AjaxWebElement response = driver.findElement(RESPONSE_AREA);
+ assertTrue("Response area should contain information about setting starting price.", response.getValue().contains(SET_STARTING_PRICE_RESPONSE));
+ }
+
+ @Test(dependsOnMethods = {
+ "testLoginService", "testCreateNewAuction"
+ })
+ public void getAuctionDetailsTest()
+ {
+ loginService();
+ createNewAuctionService();
+
+ driver.findElement(GET_AUCTION_DETAILS_LINK).clickAndWait();
+ driver.findElement(INVOKE_SERVICE_BUTTON).clickAndWait();
+
+ AjaxWebElement response = driver.findElement(RESPONSE_AREA);
+ assertTrue("Response area should contain auction details.", response.getValue().contains(AUCTION_DETAILS_PRICE_RESPONSE));
+ }
+
+ @Test(dependsOnMethods = {
+ "testLoginService"
+ })
+ public void logOutTest()
+ {
+ loginService();
+ driver.findElement(LOGOUT_LINK).clickAndWait();
+ driver.findElement(INVOKE_SERVICE_BUTTON).clickAndWait();
+
+ AjaxWebElement response = driver.findElement(RESPONSE_AREA);
+ assertTrue("Response area should contain logout confirmation.", response.getValue().contains(LOGOUT_RESPONSE));
+ }
+
+ @Test(dependsOnMethods = {
+ "testLoginService", "testCreateNewAuction"
+ })
+ public void confirmAuctionTest()
+ {
+ loginService();
+ createNewAuctionService();
+ confirmAuctionService();
+
+ AjaxWebElement response = driver.findElement(RESPONSE_AREA);
+ assertTrue("Response area should contain information about confirmation.", response.getValue().contains(CONFIRMATION_RESPONSE));
+ }
+
+ /**
+ * Goes to web services page and logs user in
+ */
+ protected void loginService()
+ {
+
+ String username = "demo";
+ String password = "demo";
+
+ driver.get(serverURL + contextPath);
+ driver.findElement(HERE_LINK).click();
+
+ driver.findElement(By.partialLinkText("Login")).clickAndWait();
+
+ driver.findElement(LOGIN_INPUT_USERNAME).clearAndSendKeys(username);
+ driver.findElement(LOGIN_INPUT_PASSWORD).clearAndSendKeys(password);
+
+ driver.findElement(INVOKE_SERVICE_BUTTON).clickAndWait();
+ }
+
+ protected void confirmAuctionService()
+ {
+ driver.findElement(CONFIRM_AUCTION_LINK).clickAndWait();
+ driver.findElement(INVOKE_SERVICE_BUTTON).clickAndWait();
+ }
+
+ protected void createNewAuctionService()
+ {
+ String title = "Animals";
+ String description = "You can buy an animal here";
+ String categoryId = "6";
+ driver.findElement(CREATE_NEW_AUCTION_LINK).clickAndWait();
+ driver.findElement(AUCTION_TITLE).clearAndSendKeys(title);
+ driver.findElement(AUCTION_DESCRIPTION).clearAndSendKeys(description);
+ driver.findElement(AUCTION_CATEGORY_ID).clearAndSendKeys(categoryId);
+ driver.findElement(INVOKE_SERVICE_BUTTON).clickAndWait();
+ }
+
+}
Added: branches/community/Seam_2_2/src/test/ftest/src/main/org/jboss/seam/example/common/test/webdriver/AjaxWebDriver.java
===================================================================
--- branches/community/Seam_2_2/src/test/ftest/src/main/org/jboss/seam/example/common/test/webdriver/AjaxWebDriver.java (rev 0)
+++ branches/community/Seam_2_2/src/test/ftest/src/main/org/jboss/seam/example/common/test/webdriver/AjaxWebDriver.java 2010-03-24 12:36:35 UTC (rev 12261)
@@ -0,0 +1,19 @@
+package org.jboss.seam.example.common.test.webdriver;
+
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebDriver;
+
+/**
+ * Modifies WebDriver to return elements with enhanced AJAX functionality
+ *
+ * @author kpiwko
+ *
+ */
+public interface AjaxWebDriver extends WebDriver
+{
+
+ //@Override
+ public AjaxWebElement findElement(By by);
+
+ public void setWaitTime(int millis);
+}
Added: branches/community/Seam_2_2/src/test/ftest/src/main/org/jboss/seam/example/common/test/webdriver/AjaxWebDriverFactory.java
===================================================================
--- branches/community/Seam_2_2/src/test/ftest/src/main/org/jboss/seam/example/common/test/webdriver/AjaxWebDriverFactory.java (rev 0)
+++ branches/community/Seam_2_2/src/test/ftest/src/main/org/jboss/seam/example/common/test/webdriver/AjaxWebDriverFactory.java 2010-03-24 12:36:35 UTC (rev 12261)
@@ -0,0 +1,41 @@
+package org.jboss.seam.example.common.test.webdriver;
+
+/**
+ * Creates appropriate WebDriver driver according to passed string.
+ * To hold a compatibility with Selenium, it is able to use Selenium
+ * based browser names
+ * @author kpiwko
+ */
+public class AjaxWebDriverFactory
+{
+ public static enum Browser
+ {
+ firefox
+ {
+ //@Override
+ public AjaxWebDriver getDriver()
+ {
+ return new FirefoxAjaxDriver();
+ }
+ };
+
+ public abstract AjaxWebDriver getDriver();
+ }
+
+ public static final AjaxWebDriver getDriver(String browser) throws IllegalArgumentException, NullPointerException
+ {
+ if(browser.contains("firefox")) {
+ return Browser.firefox.getDriver();
+ }
+
+ return Browser.valueOf(browser).getDriver();
+ }
+
+ public static final String availableBrowsers()
+ {
+ StringBuilder sb = new StringBuilder();
+ for (Browser b : Browser.values())
+ sb.append("'").append(b.toString()).append("' ");
+ return sb.toString();
+ }
+}
Added: branches/community/Seam_2_2/src/test/ftest/src/main/org/jboss/seam/example/common/test/webdriver/AjaxWebDriverTest.java
===================================================================
--- branches/community/Seam_2_2/src/test/ftest/src/main/org/jboss/seam/example/common/test/webdriver/AjaxWebDriverTest.java (rev 0)
+++ branches/community/Seam_2_2/src/test/ftest/src/main/org/jboss/seam/example/common/test/webdriver/AjaxWebDriverTest.java 2010-03-24 12:36:35 UTC (rev 12261)
@@ -0,0 +1,51 @@
+package org.jboss.seam.example.common.test.webdriver;
+
+import static org.testng.Assert.fail;
+
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Parameters;
+
+/**
+ * Abstract class for all WebDriver tests. Provides running a WebDriverInstance
+ * before each executed test and shuts it down after its execution.
+ *
+ * @author kpiwko
+ *
+ */
+public abstract class AjaxWebDriverTest
+{
+ protected AjaxWebDriver driver;
+ protected String serverURL;
+ protected String contextPath;
+
+ @BeforeMethod
+ @Parameters(value = {
+ "browser", "server.url", "context.path"
+ })
+ public void createDriver(String browser, String serverURL, String contextPath)
+ {
+ try
+ {
+ this.driver = AjaxWebDriverFactory.getDriver(browser);
+ }
+ catch (IllegalArgumentException e)
+ {
+ fail("Unable to instantiate browser of type: " + browser + ", available browsers are: " + AjaxWebDriverFactory.availableBrowsers());
+ }
+ catch (NullPointerException e)
+ {
+ fail("Unable to instantiate browser of type: " + browser + ", available browsers are: " + AjaxWebDriverFactory.availableBrowsers());
+ }
+
+ this.serverURL = serverURL;
+ this.contextPath = contextPath;
+ }
+
+ @AfterMethod
+ public void closeDriver()
+ {
+ driver.close();
+ }
+
+}
Added: branches/community/Seam_2_2/src/test/ftest/src/main/org/jboss/seam/example/common/test/webdriver/AjaxWebElement.java
===================================================================
--- branches/community/Seam_2_2/src/test/ftest/src/main/org/jboss/seam/example/common/test/webdriver/AjaxWebElement.java (rev 0)
+++ branches/community/Seam_2_2/src/test/ftest/src/main/org/jboss/seam/example/common/test/webdriver/AjaxWebElement.java 2010-03-24 12:36:35 UTC (rev 12261)
@@ -0,0 +1,25 @@
+package org.jboss.seam.example.common.test.webdriver;
+
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebElement;
+
+/**
+ * Adds AJAX functionality to an ordinary WebElement
+ *
+ * @author kpiwko
+ *
+ */
+public interface AjaxWebElement extends WebElement
+{
+
+ public static final int DEFAULT_WAIT_TIME = 3000;
+
+ //@Override
+ public AjaxWebElement findElement(By by);
+
+ public void setWaitTime(int millis);
+
+ public void clickAndWait();
+
+ public void clearAndSendKeys(CharSequence... keysToSend);
+}
Added: branches/community/Seam_2_2/src/test/ftest/src/main/org/jboss/seam/example/common/test/webdriver/DelegatedWebElement.java
===================================================================
--- branches/community/Seam_2_2/src/test/ftest/src/main/org/jboss/seam/example/common/test/webdriver/DelegatedWebElement.java (rev 0)
+++ branches/community/Seam_2_2/src/test/ftest/src/main/org/jboss/seam/example/common/test/webdriver/DelegatedWebElement.java 2010-03-24 12:36:35 UTC (rev 12261)
@@ -0,0 +1,134 @@
+package org.jboss.seam.example.common.test.webdriver;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebElement;
+
+/**
+ * Adds AjaxWebElement functionality to an ordinary WebElement
+ *
+ * @author kpiwko
+ *
+ */
+public class DelegatedWebElement implements AjaxWebElement {
+
+ private int waitTime;
+ private WebElement element;
+
+ public DelegatedWebElement(WebElement element) {
+ this(element, DEFAULT_WAIT_TIME);
+ }
+
+ public DelegatedWebElement(WebElement element, int waitTime) {
+ this.element = element;
+ this.waitTime = waitTime;
+ }
+
+ //@Override
+ public void clear() {
+ element.clear();
+ }
+
+ //@Override
+ public void clearAndSendKeys(CharSequence...keysToSend) {
+ element.clear();
+ element.sendKeys(keysToSend);
+ }
+
+ //@Override
+ public void click() {
+ element.click();
+ }
+
+ //@Override
+ public void clickAndWait() {
+ element.click();
+ try {
+ Thread.sleep(waitTime);
+ } catch (InterruptedException e) {
+ }
+ }
+
+ //@Override
+ public AjaxWebElement findElement(By by) {
+ return new DelegatedWebElement(element.findElement(by));
+ }
+
+ //@Override
+ public List<WebElement> findElements(By by) {
+ List<WebElement> elements = new ArrayList<WebElement>();
+ List<WebElement> original = element.findElements(by);
+ if (original == null || original.size() == 0)
+ return Collections.emptyList();
+
+ for (WebElement e : original)
+ elements.add(new DelegatedWebElement(e));
+
+ return elements;
+ }
+
+ //@Override
+ public String getAttribute(String name) {
+ return element.getAttribute(name);
+ }
+
+ @Deprecated
+ //@Override
+ public String getElementName() {
+ return element.getElementName();
+ }
+
+ //@Override
+ public String getTagName() {
+ return element.getTagName();
+ }
+
+ //@Override
+ public String getText() {
+ return element.getText();
+ }
+
+ //@Override
+ public String getValue() {
+ return element.getValue();
+ }
+
+ //@Override
+ public boolean isEnabled() {
+ return element.isEnabled();
+ }
+
+ //@Override
+ public boolean isSelected() {
+ return element.isSelected();
+ }
+
+ //@Override
+ public void sendKeys(CharSequence... keysToSend) {
+ element.sendKeys(keysToSend);
+ }
+
+ //@Override
+ public void setSelected() {
+ element.setSelected();
+ }
+
+ //@Override
+ public void setWaitTime(int millis) {
+ this.waitTime = millis;
+ }
+
+ //@Override
+ public void submit() {
+ element.submit();
+ }
+
+ //@Override
+ public boolean toggle() {
+ return element.toggle();
+ }
+
+}
Added: branches/community/Seam_2_2/src/test/ftest/src/main/org/jboss/seam/example/common/test/webdriver/FirefoxAjaxDriver.java
===================================================================
--- branches/community/Seam_2_2/src/test/ftest/src/main/org/jboss/seam/example/common/test/webdriver/FirefoxAjaxDriver.java (rev 0)
+++ branches/community/Seam_2_2/src/test/ftest/src/main/org/jboss/seam/example/common/test/webdriver/FirefoxAjaxDriver.java 2010-03-24 12:36:35 UTC (rev 12261)
@@ -0,0 +1,32 @@
+package org.jboss.seam.example.common.test.webdriver;
+
+import org.openqa.selenium.By;
+import org.openqa.selenium.firefox.FirefoxDriver;
+
+public class FirefoxAjaxDriver extends FirefoxDriver implements AjaxWebDriver
+{
+
+ private int waitTime;
+
+ public FirefoxAjaxDriver()
+ {
+ this(AjaxWebElement.DEFAULT_WAIT_TIME);
+ }
+
+ public FirefoxAjaxDriver(int waitTime)
+ {
+ this.waitTime = waitTime;
+ }
+
+ //@Override
+ public AjaxWebElement findElement(By by)
+ {
+ return new DelegatedWebElement(super.findElement(by), waitTime);
+ }
+
+ //@Override
+ public void setWaitTime(int millis)
+ {
+ this.waitTime = millis;
+ }
+}
14 years, 9 months
Seam SVN: r12260 - in modules/security/trunk: core and 1 other directories.
by seam-commits@lists.jboss.org
Author: shane.bryzak(a)jboss.com
Date: 2010-03-24 07:27:19 -0400 (Wed, 24 Mar 2010)
New Revision: 12260
Modified:
modules/security/trunk/core/pom.xml
modules/security/trunk/core/src/main/java/org/jboss/seam/security/permission/RuleBasedPermissionResolver.java
modules/security/trunk/pom.xml
Log:
fix compiler errors, add missing dependencies
Modified: modules/security/trunk/core/pom.xml
===================================================================
--- modules/security/trunk/core/pom.xml 2010-03-24 09:40:27 UTC (rev 12259)
+++ modules/security/trunk/core/pom.xml 2010-03-24 11:27:19 UTC (rev 12260)
@@ -37,6 +37,21 @@
<scope>provided</scope>
</dependency>
+ <dependency>
+ <groupId>javax.persistence</groupId>
+ <artifactId>persistence-api</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.drools</groupId>
+ <artifactId>drools-core</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.hibernate</groupId>
+ <artifactId>hibernate-core</artifactId>
+ </dependency>
+
</dependencies>
<build>
Modified: modules/security/trunk/core/src/main/java/org/jboss/seam/security/permission/RuleBasedPermissionResolver.java
===================================================================
--- modules/security/trunk/core/src/main/java/org/jboss/seam/security/permission/RuleBasedPermissionResolver.java 2010-03-24 09:40:27 UTC (rev 12259)
+++ modules/security/trunk/core/src/main/java/org/jboss/seam/security/permission/RuleBasedPermissionResolver.java 2010-03-24 11:27:19 UTC (rev 12260)
@@ -18,7 +18,7 @@
import org.drools.RuleBase;
import org.drools.StatefulSession;
import org.drools.ClassObjectFilter;
-import org.jboss.seam.drools.SeamGlobalResolver;
+//import org.jboss.seam.drools.SeamGlobalResolver;
import org.jboss.seam.security.Identity;
import org.jboss.seam.security.Role;
import org.jboss.seam.security.events.LoggedOutEvent;
@@ -57,7 +57,7 @@
if (getSecurityRules() != null)
{
setSecurityContext(getSecurityRules().newStatefulSession(false));
- getSecurityContext().setGlobalResolver(new SeamGlobalResolver(getSecurityContext().getGlobalResolver()));
+ //getSecurityContext().setGlobalResolver(new SeamGlobalResolver(getSecurityContext().getGlobalResolver()));
}
}
Modified: modules/security/trunk/pom.xml
===================================================================
--- modules/security/trunk/pom.xml 2010-03-24 09:40:27 UTC (rev 12259)
+++ modules/security/trunk/pom.xml 2010-03-24 11:27:19 UTC (rev 12260)
@@ -41,38 +41,47 @@
<dependency>
<groupId>javax.el</groupId>
<artifactId>el-api</artifactId>
+ <version>2.2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.persistence</groupId>
<artifactId>persistence-api</artifactId>
+ <version>1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
- <scope>provided</scope>
+ <version>1.0.0.GA</version>
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-core</artifactId>
+ <version>5.0.1</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
- <scope>provided</scope>
+ <version>3.3.2.GA</version>
</dependency>
<dependency>
<groupId>javax.enterprise</groupId>
<artifactId>cdi-api</artifactId>
- <scope>provided</scope>
+ <version>1.0-SP1</version>
</dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ <version>1.5.10</version>
+ </dependency>
+
</dependencies>
</dependencyManagement>
14 years, 9 months
Seam SVN: r12259 - modules/security/trunk.
by seam-commits@lists.jboss.org
Author: shane.bryzak(a)jboss.com
Date: 2010-03-24 05:40:27 -0400 (Wed, 24 Mar 2010)
New Revision: 12259
Added:
modules/security/trunk/assembly.xml
modules/security/trunk/lgpl.txt
modules/security/trunk/readme.txt
Modified:
modules/security/trunk/pom.xml
Log:
add build and distro related stuff
Added: modules/security/trunk/assembly.xml
===================================================================
--- modules/security/trunk/assembly.xml (rev 0)
+++ modules/security/trunk/assembly.xml 2010-03-24 09:40:27 UTC (rev 12259)
@@ -0,0 +1,69 @@
+<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd">
+ <id>bin</id>
+ <formats>
+ <format>zip</format>
+ </formats>
+ <includeBaseDirectory>false</includeBaseDirectory>
+
+ <fileSets>
+ <fileSet>
+ <directory>core/target/site/apidocs</directory>
+ <outputDirectory>seam-security/doc/api</outputDirectory>
+ <includes>
+ <include>**</include>
+ </includes>
+ </fileSet>
+
+ <fileSet>
+ <directory>examples</directory>
+ <outputDirectory>seam-security/examples</outputDirectory>
+ <useDefaultExcludes>true</useDefaultExcludes>
+ <includes>
+ <include>seamspace/pom.xml</include>
+ <include>seamspace/src/**</include>
+ </includes>
+ </fileSet>
+
+ <fileSet>
+ <directory>.</directory>
+ <outputDirectory>seam-security</outputDirectory>
+ <includes>
+ <include>readme.txt</include>
+ <include>lgpl.txt</include>
+ </includes>
+ </fileSet>
+
+ <fileSet>
+ <directory>core/src/main/java</directory>
+ <outputDirectory>seam-security/source</outputDirectory>
+ <includes>
+ <include>**</include>
+ </includes>
+ </fileSet>
+ </fileSets>
+
+ <moduleSets>
+ <moduleSet>
+ <includes>
+ <include>org.jboss.seam.security:seam-security-core:jar</include>
+ </includes>
+ <binaries>
+ <outputDirectory>seam-security/lib</outputDirectory>
+ <unpack>false</unpack>
+ </binaries>
+ </moduleSet>
+
+ <moduleSet>
+ <includes>
+ <include>org.jboss.seam.security:seam-security-reference-guide</include>
+ </includes>
+ <binaries>
+ <outputDirectory>seam-security/doc/reference</outputDirectory>
+ <unpack>true</unpack>
+ </binaries>
+ </moduleSet>
+
+ </moduleSets>
+</assembly>
Added: modules/security/trunk/lgpl.txt
===================================================================
--- modules/security/trunk/lgpl.txt (rev 0)
+++ modules/security/trunk/lgpl.txt 2010-03-24 09:40:27 UTC (rev 12259)
@@ -0,0 +1,504 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
+
+
Modified: modules/security/trunk/pom.xml
===================================================================
--- modules/security/trunk/pom.xml 2010-03-24 09:39:28 UTC (rev 12258)
+++ modules/security/trunk/pom.xml 2010-03-24 09:40:27 UTC (rev 12259)
@@ -14,44 +14,66 @@
<packaging>pom</packaging>
<version>3.0.0-SNAPSHOT</version>
<name>Seam Security Parent</name>
-
- <dependencyManagement>
- <dependency>
- <groupId>javax.el</groupId>
- <artifactId>el-api</artifactId>
- <scope>provided</scope>
- </dependency>
- <dependency>
- <groupId>javax.persistence</groupId>
- <artifactId>persistence-api</artifactId>
- <scope>provided</scope>
- </dependency>
+ <modules>
+ <module>core</module>
+ <module>docs</module>
+ <module>examples/seamspace</module>
+ </modules>
- <!-- Is this an acceptable dependency? -->
- <dependency>
- <groupId>javax.validation</groupId>
- <artifactId>validation-api</artifactId>
- <scope>provided</scope>
- </dependency>
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <version>2.2-beta-5</version>
+ <configuration>
+ <descriptors>
+ <descriptor>assembly.xml</descriptor>
+ </descriptors>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+ <dependencyManagement>
+ <dependencies>
- <dependency>
- <groupId>org.drools</groupId>
- <artifactId>drools-core</artifactId>
- </dependency>
+ <dependency>
+ <groupId>javax.el</groupId>
+ <artifactId>el-api</artifactId>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>javax.persistence</groupId>
+ <artifactId>persistence-api</artifactId>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>javax.validation</groupId>
+ <artifactId>validation-api</artifactId>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.drools</groupId>
+ <artifactId>drools-core</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.hibernate</groupId>
+ <artifactId>hibernate-core</artifactId>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>javax.enterprise</groupId>
+ <artifactId>cdi-api</artifactId>
+ <scope>provided</scope>
+ </dependency>
- <dependency>
- <groupId>org.hibernate</groupId>
- <artifactId>hibernate-core</artifactId>
- <scope>provided</scope>
- </dependency>
-
- <dependency>
- <groupId>javax.enterprise</groupId>
- <artifactId>cdi-api</artifactId>
- <scope>provided</scope>
- </dependency>
-
+ </dependencies>
</dependencyManagement>
<scm>
Added: modules/security/trunk/readme.txt
===================================================================
--- modules/security/trunk/readme.txt (rev 0)
+++ modules/security/trunk/readme.txt 2010-03-24 09:40:27 UTC (rev 12259)
@@ -0,0 +1,64 @@
+Seam Security 3.0.0 Beta 1
+==========================
+
+Seam Security provides a number of features for securing your CDI-based application.
+
+
+Contents of distribution
+========================
+
+doc/
+
+ API Docs and reference guide.
+
+examples/
+
+ Seam Security Examples
+
+lib/
+
+ Seam Security jar files
+
+Licensing
+=========
+
+This distribution, as a whole, is licensed under the terms of the GNU Lesser General Public License
+(LGPL) Version 2.1, the text of which is contained in the file lgpl.txt.
+
+Seam Security URLs
+==================
+
+Seam Framework Home Page: http://www.seamframework.org
+Downloads: http://www.seamframework.org/Download/SeamDownloads
+Forums: http://www.seamframework.org/Community/SeamUsers
+Source Code: http://anonsvn.jboss.org/repos/seam/modules/security/
+Issue Tracking: http://jira.jboss.org/jira/browse/SEAMSECURITY
+
+Release Notes
+=============
+
+Version 3.0.0 Beta 1
+--------------------
+First beta release of Seam Security 3.x, ported from Seam 2.x to CDI.
+
+
+* If using Maven, some artifacts may only be available in the JBoss Repository. To allow Seam Security to correctly function, add the JBoss Repository to Maven. Edit your ~/.m2/settings.xml, and add the following entry:
+
+ <profile>
+ <id>jboss.repository</id>
+ <activation>
+ <activeByDefault>true</activeByDefault>
+ </activation>
+ <repositories>
+ <repository>
+ <id>repository.jboss.org</id>
+ <url>http://repository.jboss.org/maven2</url>
+ <releases>
+ <enabled>true</enabled>
+ </releases>
+ <snapshots>
+ <enabled>false</enabled>
+ </snapshots>
+ </repository>
+ </repositories>
+ </profile>
14 years, 9 months
Seam SVN: r12258 - modules/remoting/trunk.
by seam-commits@lists.jboss.org
Author: shane.bryzak(a)jboss.com
Date: 2010-03-24 05:39:28 -0400 (Wed, 24 Mar 2010)
New Revision: 12258
Modified:
modules/remoting/trunk/assembly.xml
modules/remoting/trunk/readme.txt
Log:
update JIRA URL
Modified: modules/remoting/trunk/assembly.xml
===================================================================
--- modules/remoting/trunk/assembly.xml 2010-03-24 09:25:41 UTC (rev 12257)
+++ modules/remoting/trunk/assembly.xml 2010-03-24 09:39:28 UTC (rev 12258)
@@ -10,7 +10,7 @@
<fileSets>
<fileSet>
<directory>core/target/site/apidocs</directory>
- <outputDirectory>seam-remoting/doc/apidocs</outputDirectory>
+ <outputDirectory>seam-remoting/doc/api</outputDirectory>
<includes>
<include>**</include>
</includes>
Modified: modules/remoting/trunk/readme.txt
===================================================================
--- modules/remoting/trunk/readme.txt 2010-03-24 09:25:41 UTC (rev 12257)
+++ modules/remoting/trunk/readme.txt 2010-03-24 09:39:28 UTC (rev 12258)
@@ -32,7 +32,7 @@
Downloads: http://www.seamframework.org/Download/SeamDownloads
Forums: http://www.seamframework.org/Community/SeamUsers
Source Code: http://anonsvn.jboss.org/repos/seam/modules/remoting/
-Issue Tracking: http://jira.jboss.org/jira/browse/JBSEAM
+Issue Tracking: http://jira.jboss.org/jira/browse/SEAMREMOTING
Release Notes
=============
14 years, 9 months
Seam SVN: r12257 - in modules/security/trunk: core and 3 other directories.
by seam-commits@lists.jboss.org
Author: shane.bryzak(a)jboss.com
Date: 2010-03-24 05:25:41 -0400 (Wed, 24 Mar 2010)
New Revision: 12257
Added:
modules/security/trunk/core/pom.xml
modules/security/trunk/docs/
modules/security/trunk/docs/README.TXT
modules/security/trunk/docs/en-US/
modules/security/trunk/docs/en-US/master.xml
modules/security/trunk/docs/pom.xml
modules/security/trunk/examples/
modules/security/trunk/examples/seamspace/
Log:
create dir structure, core pom
Added: modules/security/trunk/core/pom.xml
===================================================================
--- modules/security/trunk/core/pom.xml (rev 0)
+++ modules/security/trunk/core/pom.xml 2010-03-24 09:25:41 UTC (rev 12257)
@@ -0,0 +1,52 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.jboss.seam.security</groupId>
+ <artifactId>seam-security-parent</artifactId>
+ <version>3.0.0-SNAPSHOT</version>
+ </parent>
+
+ <groupId>org.jboss.seam.security</groupId>
+ <artifactId>seam-security-core</artifactId>
+ <version>3.0.0-SNAPSHOT</version>
+ <packaging>jar</packaging>
+ <name>Seam Security Core</name>
+
+ <dependencies>
+ <dependency>
+ <groupId>javax.el</groupId>
+ <artifactId>el-api</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>javax.validation</groupId>
+ <artifactId>validation-api</artifactId>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>javax.enterprise</groupId>
+ <artifactId>cdi-api</artifactId>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ <scope>provided</scope>
+ </dependency>
+
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <version>2.6.1</version>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
Added: modules/security/trunk/docs/README.TXT
===================================================================
--- modules/security/trunk/docs/README.TXT (rev 0)
+++ modules/security/trunk/docs/README.TXT 2010-03-24 09:25:41 UTC (rev 12257)
@@ -0,0 +1,3 @@
+To build the Seam Security docs run the following command:
+
+mvn clean install
Added: modules/security/trunk/docs/en-US/master.xml
===================================================================
--- modules/security/trunk/docs/en-US/master.xml (rev 0)
+++ modules/security/trunk/docs/en-US/master.xml 2010-03-24 09:25:41 UTC (rev 12257)
@@ -0,0 +1,12 @@
+<?xml version='1.0' encoding="utf-8"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
+ "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [ ]>
+<book lang="en">
+
+ <toc/>
+
+ <title>Seam Remoting</title>
+ <xi:include href="remoting-general.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
+ <xi:include href="remoting-model.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
+
+</book>
\ No newline at end of file
Added: modules/security/trunk/docs/pom.xml
===================================================================
--- modules/security/trunk/docs/pom.xml (rev 0)
+++ modules/security/trunk/docs/pom.xml 2010-03-24 09:25:41 UTC (rev 12257)
@@ -0,0 +1,135 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.jboss.weld</groupId>
+ <artifactId>weld-parent</artifactId>
+ <version>8</version>
+ </parent>
+
+ <groupId>org.jboss.seam.security</groupId>
+ <artifactId>seam-security-reference-guide</artifactId>
+ <version>3.0.0-SNAPSHOT</version>
+ <packaging>jdocbook</packaging>
+ <name>Seam Security Reference Guide</name>
+
+ <pluginRepositories>
+ <pluginRepository>
+ <id>repository.jboss.org</id>
+ <name>JBoss Repository</name>
+ <url>http://repository.jboss.org/maven2</url>
+ </pluginRepository>
+ </pluginRepositories>
+ <repositories>
+ <repository>
+ <id>repository.jboss.org</id>
+ <name>JBoss Repository</name>
+ <url>http://repository.jboss.org/maven2</url>
+ </repository>
+ </repositories>
+
+ <properties>
+ <pdf.name>security-reference.pdf</pdf.name>
+ <weld.docbook.version>1.1.1-Beta5</weld.docbook.version>
+ </properties>
+
+ <build>
+ <defaultGoal>process-classes</defaultGoal>
+ <plugins>
+ <plugin>
+ <artifactId>maven-deploy-plugin</artifactId>
+ <configuration>
+ <skip>true</skip>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <groupId>org.jboss.maven.plugins</groupId>
+ <artifactId>maven-jdocbook-plugin</artifactId>
+ </plugin>
+ <plugin>
+ <artifactId>maven-antrun-plugin</artifactId>
+ <executions>
+ <execution>
+ <phase>process-classes</phase>
+ <configuration>
+ <tasks>
+ <copy file="${basedir}/target/docbook/publish/en-US/pdf/${pdf.name}" todir="${basedir}" />
+ </tasks>
+ </configuration>
+ <goals>
+ <goal>run</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>build-helper-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>attach-zip</id>
+ <phase>package</phase>
+ <goals>
+ <goal>attach-artifact</goal>
+ </goals>
+ <configuration>
+ <artifacts>
+ <artifact>
+ <file>${project.build.outputDirectory}/${project.artifactId}-${project.version}.war</file>
+ <type>war</type>
+ </artifact>
+ </artifacts>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+
+ <profiles>
+
+ <profile>
+ <id>translations</id>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.jboss.maven.plugins</groupId>
+ <artifactId>maven-jdocbook-plugin</artifactId>
+
+ <executions>
+ <execution>
+ <phase>process-resources</phase>
+ <goals>
+ <goal>translate</goal>
+ </goals>
+ </execution>
+ </executions>
+
+ <configuration>
+ <translations>
+ <!--translation>it-IT</translation>
+ <translation>zh-CN</translation>
+ <translation>zh-TW</translation>
+ <translation>es-ES</translation>
+ <translation>ko-KR</translation>
+
+ <translation>de-DE</translation>
+ <translation>pt-BR</translation-->
+ </translations>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+
+ </profiles>
+
+
+ <scm>
+ <connection>scm:svn:http://anonsvn.jboss.org/repos/seam/modules/security/trunk/docs</connection>
+ <developerConnection>scm:svn:https://svn.jboss.org/repos/seam/modules/security/trunk/docs</developerConnection>
+ <url>http://fisheye.jboss.org/browse/seam/modules/security/docs</url>
+ </scm>
+
+</project>
14 years, 9 months
Seam SVN: r12256 - in modules/security/trunk: core and 1 other directory.
by seam-commits@lists.jboss.org
Author: shane.bryzak(a)jboss.com
Date: 2010-03-24 05:14:40 -0400 (Wed, 24 Mar 2010)
New Revision: 12256
Added:
modules/security/trunk/core/
modules/security/trunk/core/src/
Removed:
modules/security/trunk/src/
Modified:
modules/security/trunk/pom.xml
Log:
cleanup parent pom, dir structure
Copied: modules/security/trunk/core/src (from rev 12255, modules/security/trunk/src)
Modified: modules/security/trunk/pom.xml
===================================================================
--- modules/security/trunk/pom.xml 2010-03-24 08:44:41 UTC (rev 12255)
+++ modules/security/trunk/pom.xml 2010-03-24 09:14:40 UTC (rev 12256)
@@ -4,56 +4,19 @@
<modelVersion>4.0.0</modelVersion>
<parent>
- <artifactId>seam-parent</artifactId>
- <groupId>org.jboss.seam</groupId>
- <version>3.0.0-SNAPSHOT</version>
+ <artifactId>weld-parent</artifactId>
+ <groupId>org.jboss.weld</groupId>
+ <version>8</version>
</parent>
- <artifactId>seam-security</artifactId>
- <packaging>jar</packaging>
+ <groupId>org.jboss.seam.security</groupId>
+ <artifactId>seam-security-parent</artifactId>
+ <packaging>pom</packaging>
<version>3.0.0-SNAPSHOT</version>
- <name>Seam Security</name>
+ <name>Seam Security Parent</name>
- <!-- Snapshots repo to get parent -->
- <repositories>
- <repository>
- <id>oss.sonatype.org/jboss-snapshots</id>
- <name>JBoss (Nexus) Snapshots Repository</name>
- <url>http://oss.sonatype.org/content/repositories/jboss-snapshots</url>
- <releases>
- <enabled>false</enabled>
- </releases>
- <snapshots>
- <enabled>true</enabled>
- <updatePolicy>never</updatePolicy>
- </snapshots>
- </repository>
- </repositories>
-
- <prerequisites>
- <maven>2.0.10</maven>
- </prerequisites>
-
-
- <properties>
- <seam.version>3.0.0-SNAPSHOT</seam.version>
- </properties>
-
- <dependencies>
-
+ <dependencyManagement>
<dependency>
- <groupId>javax.faces</groupId>
- <artifactId>jsf-api</artifactId>
- <scope>provided</scope>
- </dependency>
-
- <dependency>
- <groupId>org.jboss.ejb3</groupId>
- <artifactId>jboss-ejb3-api</artifactId>
- <scope>provided</scope>
- </dependency>
-
- <dependency>
<groupId>javax.el</groupId>
<artifactId>el-api</artifactId>
<scope>provided</scope>
@@ -84,38 +47,13 @@
</dependency>
<dependency>
- <groupId>org.jboss.seam</groupId>
- <artifactId>seam-drools</artifactId>
- </dependency>
-
-<!-- <dependency>-->
-<!-- <groupId>org.jboss.seam</groupId>-->
-<!-- <artifactId>seam-international</artifactId>-->
-<!-- </dependency>-->
-
- <!--
- <dependency>
- <groupId>org.jboss.seam</groupId>
- <artifactId>seam-faces</artifactId>
- </dependency>
- -->
-
- <!--
- <dependency>
- <groupId>org.jboss.seam</groupId>
- <artifactId>seam-persistence</artifactId>
- </dependency>
- -->
-
- <dependency>
<groupId>javax.enterprise</groupId>
<artifactId>cdi-api</artifactId>
<scope>provided</scope>
</dependency>
- </dependencies>
+ </dependencyManagement>
-
<scm>
<connection>scm:svn:http://anonsvn.jboss.org/repos/seam/modules/security/trunk</connection>
<developerConnection>scm:svn:https://svn.jboss.org/repos/seam/modules/security/trunk</developerConnection>
14 years, 9 months
Seam SVN: r12255 - in modules: servlet/trunk and 1 other directories.
by seam-commits@lists.jboss.org
Author: nickarls
Date: 2010-03-24 04:44:41 -0400 (Wed, 24 Mar 2010)
New Revision: 12255
Modified:
modules/faces/trunk/pom.xml
modules/servlet/trunk/pom.xml
modules/servlet/trunk/src/main/java/org/jboss/seam/servlet/event/ServletEventListener.java
Log:
change scope of arquillian artifact to test (was pulling in too much in deps)
lose injection in listener
include logger in servlet dep
Modified: modules/faces/trunk/pom.xml
===================================================================
--- modules/faces/trunk/pom.xml 2010-03-23 22:21:04 UTC (rev 12254)
+++ modules/faces/trunk/pom.xml 2010-03-24 08:44:41 UTC (rev 12255)
@@ -108,6 +108,7 @@
<groupId>org.jboss.arquillian.container</groupId>
<artifactId>arquillian-weld-embedded</artifactId>
<version>${arquillian.version}</version>
+ <scope>test</scope>
</dependency>
<dependency>
<groupId>org.jboss.jsfunit</groupId>
Modified: modules/servlet/trunk/pom.xml
===================================================================
--- modules/servlet/trunk/pom.xml 2010-03-23 22:21:04 UTC (rev 12254)
+++ modules/servlet/trunk/pom.xml 2010-03-24 08:44:41 UTC (rev 12255)
@@ -72,6 +72,11 @@
<artifactId>jsr250-api</artifactId>
<scope>provided</scope>
</dependency>
+ <dependency>
+ <groupId>org.jboss.weld</groupId>
+ <artifactId>weld-extensions</artifactId>
+ <version>1.0.0.Alpha1</version>
+ </dependency>
<!-- Test Dependencies -->
<dependency>
@@ -90,6 +95,7 @@
<groupId>org.jboss.arquillian.container</groupId>
<artifactId>arquillian-weld-embedded</artifactId>
<version>${arquillian.version}</version>
+ <scope>test</scope>
</dependency>
</dependencies>
Modified: modules/servlet/trunk/src/main/java/org/jboss/seam/servlet/event/ServletEventListener.java
===================================================================
--- modules/servlet/trunk/src/main/java/org/jboss/seam/servlet/event/ServletEventListener.java 2010-03-23 22:21:04 UTC (rev 12254)
+++ modules/servlet/trunk/src/main/java/org/jboss/seam/servlet/event/ServletEventListener.java 2010-03-24 08:44:41 UTC (rev 12255)
@@ -7,7 +7,6 @@
import javax.enterprise.inject.spi.BeanManager;
import javax.enterprise.util.AnnotationLiteral;
-import javax.inject.Inject;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.servlet.AsyncEvent;
@@ -43,6 +42,7 @@
import org.jboss.seam.servlet.event.qualifier.ValueUnbound;
import org.jboss.seam.servlet.event.qualifier.WillPassivate;
import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* A self-registering web-listener that propagates the events to the current CDI
@@ -54,12 +54,10 @@
@WebListener
public class ServletEventListener implements HttpSessionActivationListener, HttpSessionAttributeListener, HttpSessionBindingListener, HttpSessionListener, ServletContextListener, ServletContextAttributeListener, ServletRequestListener, ServletRequestAttributeListener, AsyncListener
{
- @Inject
private BeanManager beanManager;
-
- @Inject
- private Logger log;
+ private Logger log = LoggerFactory.getLogger(ServletEventListener.class);
+
// FIXME: hack to work around invalid binding in JBoss AS 6 M2
private static final List<String> beanManagerLocations = new ArrayList<String>()
{
@@ -72,10 +70,7 @@
public ServletEventListener()
{
- if (beanManager == null)
- {
- beanManager = lookupBeanManager();
- }
+ beanManager = lookupBeanManager();
}
private BeanManager lookupBeanManager()
14 years, 9 months