JBoss Rich Faces SVN: r524 - in trunk/sandbox/sandbox-samples: scrollable-grid-demo and 6 other directories.
by richfaces-svn-commits@lists.jboss.org
Author: abelevich
Date: 2007-04-24 13:13:22 -0400 (Tue, 24 Apr 2007)
New Revision: 524
Added:
trunk/sandbox/sandbox-samples/pom.xml
trunk/sandbox/sandbox-samples/scrollable-grid-demo/
trunk/sandbox/sandbox-samples/scrollable-grid-demo/.settings/
trunk/sandbox/sandbox-samples/scrollable-grid-demo/pom.xml
trunk/sandbox/sandbox-samples/scrollable-grid-demo/src/
trunk/sandbox/sandbox-samples/scrollable-grid-demo/src/main/
trunk/sandbox/sandbox-samples/scrollable-grid-demo/src/main/java/
trunk/sandbox/sandbox-samples/scrollable-grid-demo/src/main/resources/
trunk/sandbox/sandbox-samples/scrollable-grid-demo/src/main/webapp/
trunk/sandbox/sandbox-samples/scrollable-grid-demo/src/main/webapp/WEB-INF/
trunk/sandbox/sandbox-samples/scrollable-grid-demo/src/main/webapp/WEB-INF/faces-config.xml
trunk/sandbox/sandbox-samples/scrollable-grid-demo/src/main/webapp/WEB-INF/web.xml
trunk/sandbox/sandbox-samples/scrollable-grid-demo/src/main/webapp/index.jsp
trunk/sandbox/sandbox-samples/scrollable-grid-demo/src/main/webapp/pages/
trunk/sandbox/sandbox-samples/scrollable-grid-demo/src/main/webapp/pages/index.jsp
trunk/sandbox/sandbox-samples/scrollable-grid-demo/src/main/webapp/pages/index.xhtml
trunk/sandbox/sandbox-samples/scrollable-grid-demo/target/
trunk/sandbox/sandbox-samples/scrollable-grid-demo/target/classes/
Log:
Added: trunk/sandbox/sandbox-samples/pom.xml
===================================================================
--- trunk/sandbox/sandbox-samples/pom.xml (rev 0)
+++ trunk/sandbox/sandbox-samples/pom.xml 2007-04-24 17:13:22 UTC (rev 524)
@@ -0,0 +1,237 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<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>
+ <groupId>org.richfaces</groupId>
+ <artifactId>sandbox-samples</artifactId>
+ <packaging>pom</packaging>
+ <name>RichFaces Components Examples</name>
+ <version>3.0.1-SNAPSHOT</version>
+ <url>http://labs.jboss.com/jbossrichfaces/samples</url>
+
+ <!-- Profile to run jetty, so the tomcat jars are included in the bundle. They are not included by default -->
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.mortbay.jetty</groupId>
+ <artifactId>maven-jetty-plugin</artifactId>
+ <version>6.1.1</version>
+ <configuration>
+ <scanIntervalSeconds>10</scanIntervalSeconds>
+ <connectors>
+ <connector implementation="org.mortbay.jetty.nio.SelectChannelConnector">
+ <port>8080</port>
+ <maxIdleTime>60000</maxIdleTime>
+ </connector>
+ </connectors>
+ </configuration>
+
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <skip>true</skip>
+ </configuration>
+ <executions>
+ <execution>
+ <id>surefire-it</id>
+ <phase>integration-test</phase>
+ <goals>
+ <goal>test</goal>
+ </goals>
+ <configuration>
+ <skip>false</skip>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+
+ <dependencies>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>3.8.1</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.ajax4jsf</groupId>
+ <artifactId>ajax4jsf</artifactId>
+ <version>1.1.1-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>com.sun.facelets</groupId>
+ <artifactId>jsf-facelets</artifactId>
+ <version>1.1.12</version>
+ </dependency>
+ <dependency>
+ <groupId>javax.el</groupId>
+ <artifactId>el-api</artifactId>
+ <version>1.0</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>el-impl</groupId>
+ <artifactId>el-impl</artifactId>
+ <version>1.0</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>javax.servlet</groupId>
+ <artifactId>jstl</artifactId>
+ <version>1.0</version>
+ <scope>runtime</scope>
+ </dependency>
+ </dependencies>
+
+ <scm>
+ <connection>
+ scm:svn:http://anonsvn.jboss.org/repos/richfaces/
+ </connection>
+ <developerConnection>
+ scm:svn:https://svn.jboss.org/repos/richfaces/
+ </developerConnection>
+ <url>http://anonsvn.jboss.org/repos/richfaces/</url>
+ </scm>
+
+ <distributionManagement>
+ <downloadUrl>http://labs.jboss.com/portal/jbossrichfaces/downloads</downloadUrl>
+ <repository>
+ <id>release-repository</id>
+ <uniqueVersion>false</uniqueVersion>
+ <url>${releaseRepository}</url>
+ </repository>
+ <snapshotRepository>
+ <id>snap-repository</id>
+ <uniqueVersion>true</uniqueVersion>
+ <url>${snapshotRepository}</url>
+ </snapshotRepository>
+ </distributionManagement>
+ <pluginRepositories>
+ <pluginRepository>
+ <releases>
+ <enabled>false</enabled>
+ </releases>
+ <snapshots>
+ <enabled>true</enabled>
+ <updatePolicy>always</updatePolicy>
+ </snapshots>
+ <id>maven2-snapshots.jboss.org</id>
+ <name>Jboss Repository for Maven Snapshots</name>
+ <url>http://snapshots.jboss.com/</url>
+ </pluginRepository>
+ </pluginRepositories>
+ <repositories>
+ <repository>
+ <releases/>
+ <snapshots>
+ <enabled>false</enabled>
+ <updatePolicy>never</updatePolicy>
+ </snapshots>
+ <id>maven-repository.dev.java.net</id>
+ <name>Java.net Repository for Maven</name>
+ <url>
+ https://maven-repository.dev.java.net/nonav/repository
+ </url>
+ <layout>legacy</layout>
+ </repository>
+ <repository>
+ <releases>
+ <enabled>false</enabled>
+ </releases>
+ <snapshots>
+ <enabled>true</enabled>
+ <updatePolicy>always</updatePolicy>
+ </snapshots>
+ <id>maven2-snapshots.jboss.org</id>
+ <name>Jboss Repository for Maven Snapshots</name>
+ <url>http://snapshots.jboss.com/</url>
+ </repository>
+ </repositories>
+ <profiles>
+ <profile>
+ <id>jsf12</id>
+ <build>
+ <defaultGoal>jetty:run</defaultGoal>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>2.0</version>
+ <configuration>
+ <source>1.5</source>
+ <target>1.5</target>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ <dependencies>
+ <dependency>
+ <groupId>javax.servlet</groupId>
+ <artifactId>servlet-api</artifactId>
+ <version>2.5</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>javax.servlet.jsp</groupId>
+ <artifactId>jsp-api</artifactId>
+ <version>2.1</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>javax.faces</groupId>
+ <artifactId>jsf-api</artifactId>
+ <version>1.2_03</version>
+ </dependency>
+ <dependency>
+ <groupId>javax.faces</groupId>
+ <artifactId>jsf-impl</artifactId>
+ <version>1.2_03</version>
+ <scope>runtime</scope>
+ </dependency>
+ </dependencies>
+ </profile>
+ <profile>
+ <id>myfaces</id>
+ <properties>
+ <myfaces>1.1.5</myfaces>
+ <tomahawk>1.1.5</tomahawk>
+ </properties>
+ <build>
+ <plugins/>
+ </build>
+ <dependencies>
+ <dependency>
+ <groupId>org.ajax4jsf</groupId>
+ <artifactId>ajax4jsf</artifactId>
+ <version>1.1.1-SNAPSHOT</version>
+ <exclusions>
+ <exclusion>
+ <groupId>javax.faces</groupId>
+ <artifactId>jsf-api</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>javax.faces</groupId>
+ <artifactId>jsf-impl</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.myfaces.core</groupId>
+ <artifactId>myfaces-api</artifactId>
+ <version>${myfaces}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.myfaces.core</groupId>
+ <artifactId>myfaces-impl</artifactId>
+ <version>${myfaces}</version>
+ <scope>runtime</scope>
+ </dependency>
+ </dependencies>
+ </profile>
+ </profiles>
+ <modules>
+ <module>scrollable-grid-demo</module>
+ </modules>
+</project>
\ No newline at end of file
Added: trunk/sandbox/sandbox-samples/scrollable-grid-demo/pom.xml
===================================================================
--- trunk/sandbox/sandbox-samples/scrollable-grid-demo/pom.xml (rev 0)
+++ trunk/sandbox/sandbox-samples/scrollable-grid-demo/pom.xml 2007-04-24 17:13:22 UTC (rev 524)
@@ -0,0 +1,15 @@
+<?xml version="1.0"?><project>
+ <parent>
+ <artifactId>sandbox-samples</artifactId>
+ <groupId>org.richfaces</groupId>
+ <version>3.0.1-SNAPSHOT</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>org.richfaces</groupId>
+ <artifactId>scrollable-grid-demo</artifactId>
+ <packaging>war</packaging>
+ <name>scrollable-grid-demo Maven Webapp</name>
+ <build>
+ <finalName>scrollable-grid-demo</finalName>
+ </build>
+</project>
\ No newline at end of file
Added: trunk/sandbox/sandbox-samples/scrollable-grid-demo/src/main/webapp/WEB-INF/faces-config.xml
===================================================================
--- trunk/sandbox/sandbox-samples/scrollable-grid-demo/src/main/webapp/WEB-INF/faces-config.xml (rev 0)
+++ trunk/sandbox/sandbox-samples/scrollable-grid-demo/src/main/webapp/WEB-INF/faces-config.xml 2007-04-24 17:13:22 UTC (rev 524)
@@ -0,0 +1,10 @@
+<?xml version="1.0"?>
+<!DOCTYPE faces-config PUBLIC "-//Sun Microsystems, Inc.//DTD JavaServer Faces Config 1.1//EN"
+ "http://java.sun.com/dtd/web-facesconfig_1_1.dtd">
+<faces-config>
+ <managed-bean>
+ <managed-bean-name>bean</managed-bean-name>
+ <managed-bean-class>org.richfaces.Bean</managed-bean-class>
+ <managed-bean-scope>request</managed-bean-scope>
+ </managed-bean>
+</faces-config>
Added: trunk/sandbox/sandbox-samples/scrollable-grid-demo/src/main/webapp/WEB-INF/web.xml
===================================================================
--- trunk/sandbox/sandbox-samples/scrollable-grid-demo/src/main/webapp/WEB-INF/web.xml (rev 0)
+++ trunk/sandbox/sandbox-samples/scrollable-grid-demo/src/main/webapp/WEB-INF/web.xml 2007-04-24 17:13:22 UTC (rev 524)
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
+ <display-name>Archetype Created Web Application</display-name>
+ <context-param>
+ <param-name>javax.faces.CONFIG_FILES</param-name>
+ <param-value>/WEB-INF/faces-config.xml</param-value>
+ </context-param>
+ <context-param>
+ <param-name>javax.faces.STATE_SAVING_METHOD</param-name>
+ <param-value>server</param-value>
+ </context-param>
+ <!--
+ -->
+ <filter>
+ <display-name>Ajax4jsf Filter</display-name>
+ <filter-name>ajax4jsf</filter-name>
+ <filter-class>org.ajax4jsf.Filter</filter-class>
+ </filter>
+ <filter-mapping>
+ <filter-name>ajax4jsf</filter-name>
+ <servlet-name>Faces Servlet</servlet-name>
+ <dispatcher>REQUEST</dispatcher>
+ <dispatcher>FORWARD</dispatcher>
+ <dispatcher>INCLUDE</dispatcher>
+ </filter-mapping>
+ <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>/faces/*</url-pattern>
+ </servlet-mapping>
+ <servlet-mapping>
+ <servlet-name>Faces Servlet</servlet-name>
+ <url-pattern>*.jsf</url-pattern>
+ </servlet-mapping>
+ <login-config>
+ <auth-method>BASIC</auth-method>
+ </login-config>
+</web-app>
Added: trunk/sandbox/sandbox-samples/scrollable-grid-demo/src/main/webapp/index.jsp
===================================================================
--- trunk/sandbox/sandbox-samples/scrollable-grid-demo/src/main/webapp/index.jsp (rev 0)
+++ trunk/sandbox/sandbox-samples/scrollable-grid-demo/src/main/webapp/index.jsp 2007-04-24 17:13:22 UTC (rev 524)
@@ -0,0 +1,11 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+
+<html>
+
+<head></head>
+
+ <body>
+ <jsp:forward page="/pages/index.jsf" />
+ </body>
+
+</html>
\ No newline at end of file
Added: trunk/sandbox/sandbox-samples/scrollable-grid-demo/src/main/webapp/pages/index.jsp
===================================================================
--- trunk/sandbox/sandbox-samples/scrollable-grid-demo/src/main/webapp/pages/index.jsp (rev 0)
+++ trunk/sandbox/sandbox-samples/scrollable-grid-demo/src/main/webapp/pages/index.jsp 2007-04-24 17:13:22 UTC (rev 524)
@@ -0,0 +1,12 @@
+<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
+<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%>
+<html>
+ <head>
+ <title></title>
+ </head>
+ <body>
+ <f:view>
+
+ </f:view>
+ </body>
+</html>
Added: trunk/sandbox/sandbox-samples/scrollable-grid-demo/src/main/webapp/pages/index.xhtml
===================================================================
--- trunk/sandbox/sandbox-samples/scrollable-grid-demo/src/main/webapp/pages/index.xhtml (rev 0)
+++ trunk/sandbox/sandbox-samples/scrollable-grid-demo/src/main/webapp/pages/index.xhtml 2007-04-24 17:13:22 UTC (rev 524)
@@ -0,0 +1,12 @@
+<!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:f="http://java.sun.com/jsf/core"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:a4j="https://ajax4jsf.dev.java.net/ajax"
+ xmlns:c="http://java.sun.com/jsp/jstl/core"
+ >
+ <f:view>
+
+ </f:view>
+</html>
\ No newline at end of file
17 years, 8 months
JBoss Rich Faces SVN: r522 - trunk/sandbox/scrollable-grid.
by richfaces-svn-commits@lists.jboss.org
Author: abelevich
Date: 2007-04-24 11:28:16 -0400 (Tue, 24 Apr 2007)
New Revision: 522
Modified:
trunk/sandbox/scrollable-grid/generatescript.xml
trunk/sandbox/scrollable-grid/pom.xml
Log:
Modified: trunk/sandbox/scrollable-grid/generatescript.xml
===================================================================
--- trunk/sandbox/scrollable-grid/generatescript.xml 2007-04-24 15:28:02 UTC (rev 521)
+++ trunk/sandbox/scrollable-grid/generatescript.xml 2007-04-24 15:28:16 UTC (rev 522)
@@ -17,28 +17,29 @@
</description>
<target name="merge-scripts">
- <property name="script-path" value="org/richfaces/renderkit/html/scripts"></property>
+ <!-- <property name="script-path" value="org/richfaces/renderkit/html/scripts"></property> -->
<property name="gen-script-name" value="scrollable-grid.js"></property>
- <property name="gen-script-full-name" value="${target-dir}/${script-path}/${gen-script-name}"></property>
+ <property name="gen-script-full-name" value="${target-dir}/${gen-script-name}"></property>
<concat append="false" binary="false" destfile="${gen-script-full-name}">
- <filelist dir="${resources-dir}/${script-path}">
+ <filelist dir="${resources-dir}">
<file name="/common/prototype/ext/extend.js"/>
<file name="ClientUILib.js"/>
- <file name="/ui/common/utils/StringBuilder.js"/>
- <file name="/ui/common/utils/Validators.js"/>
- <file name="/ui/common/box/Box.js"/>
- <file name="/ui/common/box/InlineBox.js"/>
- <file name="/ui/common/utils/CustomEvent.js"/>
- <file name="/ui/common/box/ScrollableBox.js"/>
- <file name="/ui/controls/grid/DataModel.js"/>
- <file name="/ui/controls/grid/ArrayDataModel.js"/>
- <file name="/ui/layouts/LayoutManager.js"/>
- <file name="/ui/common/box/Substrate.js"/>
- <file name="/ui/controls/grid/GridLayoutManager.js"/>
- <file name="/ui/controls/grid/GridHeader.js"/>
- <file name="/ui/controls/grid/GridBody.js"/>
- <file name="/ui/controls/grid/GridFooter.js"/>
- <file name="/ui/controls/grid/CellsStrip.js"/>
+ <file name="/ClientUI/common/utils/StringBuilder.js"/>
+ <file name="/ClientUI/common/utils/Validators.js"/>
+ <file name="/ClientUI/common/box/Box.js"/>
+ <file name="/ClientUI/common/box/InlineBox.js"/>
+ <file name="/ClientUI/common/utils/CustomEvent.js"/>
+ <file name="/ClientUI/common/box/ScrollableBox.js"/>
+ <file name="/ClientUI/controls/grid/DataModel.js"/>
+ <file name="/ClientUI/controls/grid/ArrayDataModel.js"/>
+ <file name="/ClientUI/layouts/LayoutManager.js"/>
+ <file name="/ClientUI/common/box/Substrate.js"/>
+ <file name="/ClientUI/layouts/VLayoutManager.js"/>
+ <file name="/ClientUI/layouts/GridLayoutManager.js"/>
+ <file name="/ClientUI/controls/grid/GridHeader.js"/>
+ <file name="/ClientUI/controls/grid/GridBody.js"/>
+ <file name="/ClientUI/controls/grid/GridFooter.js"/>
+ <file name="/ClientUI/controls/grid/CellsStrip.js"/>
</filelist>
</concat>
</target>
Modified: trunk/sandbox/scrollable-grid/pom.xml
===================================================================
--- trunk/sandbox/scrollable-grid/pom.xml 2007-04-24 15:28:02 UTC (rev 521)
+++ trunk/sandbox/scrollable-grid/pom.xml 2007-04-24 15:28:16 UTC (rev 522)
@@ -14,9 +14,9 @@
<configuration>
<library>
<prefix>org.richfaces</prefix>
- <taglib>
- <shortName>scrollable-grid</shortName>
- </taglib>
+ <taglib>
+ <shortName>scrollable-grid</shortName>
+ </taglib>
</library>
</configuration>
<executions>
@@ -44,7 +44,7 @@
value="${project.build.directory}/generated-component/resources">
</property>
<property name="resources-dir"
- value="${basedir}/src/main/resources">
+ value="${basedir}/src/main/javascript">
</property>
</ant>
</tasks>
@@ -190,7 +190,6 @@
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.4</version>
- <scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
17 years, 8 months
JBoss Rich Faces SVN: r519 - trunk/sandbox/scrollable-grid/src/main/templates/org/richfaces.
by richfaces-svn-commits@lists.jboss.org
Author: abelevich
Date: 2007-04-24 11:27:33 -0400 (Tue, 24 Apr 2007)
New Revision: 519
Modified:
trunk/sandbox/scrollable-grid/src/main/templates/org/richfaces/scrollable-grid.jspx
Log:
Modified: trunk/sandbox/scrollable-grid/src/main/templates/org/richfaces/scrollable-grid.jspx
===================================================================
--- trunk/sandbox/scrollable-grid/src/main/templates/org/richfaces/scrollable-grid.jspx 2007-04-24 15:27:18 UTC (rev 518)
+++ trunk/sandbox/scrollable-grid/src/main/templates/org/richfaces/scrollable-grid.jspx 2007-04-24 15:27:33 UTC (rev 519)
@@ -5,12 +5,22 @@
xmlns:ui=" http://ajax4jsf.org/cdk/ui"
xmlns:u=" http://ajax4jsf.org/cdk/u"
xmlns:x=" http://ajax4jsf.org/cdk/x"
+ xmlns:h=" http://ajax4jsf.org/cdk/headers"
xmlns:vcp="http://ajax4jsf.org/cdk/vcp"
class="org.richfaces.renderkit.html.ScrollableGridRenderer"
baseclass="org.richfaces.renderkit.ScrollableGridBaseRenderer"
component="org.richfaces.component.UIScrollableGrid"
>
+ <h:styles>
+ /org/richfaces/renderkit/html/css/grid.xcss
+ </h:styles>
+
+ <h:scripts>
+ new org.ajax4jsf.framework.resource.PrototypeScript(),
+ /org/richfaces/renderkit/html/scripts/scrollable-grid.js
+ </h:scripts>
+
<div id="GridContainer" style="width:60%; height:300px;" class="ClientUI_Grid">
<div id="GridHeaderTemplate">
<table class="TestGridHeader" cellpadding="0" cellspacing="0" border="1">
@@ -23,11 +33,11 @@
<td style="width:100%;">
<table class="ClientUI_Grid_HCBodyContent" cellpadding="0" cellspacing="0" style="width:100%;">
<tr>
- <td style="font-size: 1px;" colspan="3"><div class="CustomHeaderHSep"> </div></td>
+ <td style="font-size: 1px;" colspan="3"><div class="CustomHeaderHSep"> </div></td>
</tr>
<tr>
<td class="ClientUI_Grid_HCBodyContent" align="center" width="50%">Column 2.1</td>
- <td class="CustomHeaderVSep"> </td>
+ <td class="CustomHeaderVSep">  </td>
<td class="ClientUI_Grid_HCBodyContent" align="center" width="50%">Column 2.2</td>
</tr>
</table>
@@ -54,11 +64,11 @@
<td style="width:100%;">
<table class="ClientUI_Grid_HCBodyContent" cellpadding="0" cellspacing="0" style="width:100%;">
<tr>
- <td style="font-size: 1px;" colspan="3"><div class="CustomHeaderHSep"> </div></td>
+ <td style="font-size: 1px;" colspan="3"><div class="CustomHeaderHSep"> </div></td>
</tr>
<tr>
<td class="ClientUI_Grid_HCBodyContent" align="center" width="50%">Column 6.1</td>
- <td class="CustomHeaderVSep"> </td>
+ <td class="CustomHeaderVSep">  </td>
<td class="ClientUI_Grid_HCBodyContent" align="center" width="50%">Column 6.2</td>
</tr>
</table>
17 years, 8 months
JBoss Rich Faces SVN: r518 - in trunk/sandbox/scrollable-grid/src/main/javascript: ClientUI and 9 other directories.
by richfaces-svn-commits@lists.jboss.org
Author: abelevich
Date: 2007-04-24 11:27:18 -0400 (Tue, 24 Apr 2007)
New Revision: 518
Added:
trunk/sandbox/scrollable-grid/src/main/javascript/ClientUI/common/
trunk/sandbox/scrollable-grid/src/main/javascript/ClientUI/common/box/
trunk/sandbox/scrollable-grid/src/main/javascript/ClientUI/common/box/Box.js
trunk/sandbox/scrollable-grid/src/main/javascript/ClientUI/common/box/InlineBox.js
trunk/sandbox/scrollable-grid/src/main/javascript/ClientUI/common/box/ScrollableBox.js
trunk/sandbox/scrollable-grid/src/main/javascript/ClientUI/common/box/Substrate.js
trunk/sandbox/scrollable-grid/src/main/javascript/ClientUI/common/utils/
trunk/sandbox/scrollable-grid/src/main/javascript/ClientUI/common/utils/CustomEvent.js
trunk/sandbox/scrollable-grid/src/main/javascript/ClientUI/common/utils/StringBuilder.js
trunk/sandbox/scrollable-grid/src/main/javascript/ClientUI/common/utils/Validators.js
trunk/sandbox/scrollable-grid/src/main/javascript/ClientUI/controls/
trunk/sandbox/scrollable-grid/src/main/javascript/ClientUI/controls/grid/
trunk/sandbox/scrollable-grid/src/main/javascript/ClientUI/controls/grid/ArrayDataModel.js
trunk/sandbox/scrollable-grid/src/main/javascript/ClientUI/controls/grid/CellsStrip.js
trunk/sandbox/scrollable-grid/src/main/javascript/ClientUI/controls/grid/DataModel.js
trunk/sandbox/scrollable-grid/src/main/javascript/ClientUI/controls/grid/DefaultColumnModel.js
trunk/sandbox/scrollable-grid/src/main/javascript/ClientUI/controls/grid/Grid.js
trunk/sandbox/scrollable-grid/src/main/javascript/ClientUI/controls/grid/GridBody.js
trunk/sandbox/scrollable-grid/src/main/javascript/ClientUI/controls/grid/GridFooter.js
trunk/sandbox/scrollable-grid/src/main/javascript/ClientUI/controls/grid/GridHeader.js
trunk/sandbox/scrollable-grid/src/main/javascript/ClientUI/layouts/
trunk/sandbox/scrollable-grid/src/main/javascript/ClientUI/layouts/GridLayoutManager.js
trunk/sandbox/scrollable-grid/src/main/javascript/ClientUI/layouts/LayoutManager.js
trunk/sandbox/scrollable-grid/src/main/javascript/ClientUI/layouts/VLayoutManager.js
trunk/sandbox/scrollable-grid/src/main/javascript/ClientUILib.js
trunk/sandbox/scrollable-grid/src/main/javascript/common/
trunk/sandbox/scrollable-grid/src/main/javascript/common/prototype/
trunk/sandbox/scrollable-grid/src/main/javascript/common/prototype/ext/
trunk/sandbox/scrollable-grid/src/main/javascript/common/prototype/ext/extend.js
trunk/sandbox/scrollable-grid/src/main/javascript/common/prototype/prototype.js
trunk/sandbox/scrollable-grid/src/main/javascript/common/scriptaculous/
Log:
Added: trunk/sandbox/scrollable-grid/src/main/javascript/ClientUI/common/box/Box.js
===================================================================
--- trunk/sandbox/scrollable-grid/src/main/javascript/ClientUI/common/box/Box.js (rev 0)
+++ trunk/sandbox/scrollable-grid/src/main/javascript/ClientUI/common/box/Box.js 2007-04-24 15:27:18 UTC (rev 518)
@@ -0,0 +1,251 @@
+/**
+ * Box.js Date created: 6.04.2007
+ * Copyright (c) 2007 Exadel Inc.
+ * @author Denis Morozov <dmorozov(a)exadel.com>
+ */
+ClientUILib.declarePackage("ClientUI.common.box.Box");
+
+
+/*
+ * Base class for all ui controls
+ *
+ * TODO: description of control
+ *
+ * TODO: usage description
+ * Usage:
+ * ClientUILib.declarePackage("ClientUI.common");
+ * ClientUILib.requireClass("ClientUI.common.box.Box");
+ * var ClientUI.MyControl = Class.create({
+ * CLASSDEF : {
+ * name: 'ClientUI.MyControl',
+ * parent: ClientUI.common.box.Box
+ * },
+ * initialize:function() {
+ * this.parentClass().constructor().call(this)
+ * alert("A new " + this.getClass().className + " was created")
+ * }
+ * })
+ */
+ClientUI.common.box.Box = Class.create({
+ CLASSDEF: {
+ name: 'ClientUI.common.box.Box'
+ }
+});
+
+Object.extend(ClientUI.common.box.Box.prototype, {
+
+ initialize: function(element, parentElement, dontUpdateStyles) {
+ this.element = $(element);
+ if(!this.element) {
+ this.element = $(document.createElement("div"));
+ if($(parentElement)) {
+ $(parentElement).appendChild(this.element);
+ }
+ else {
+ document.body.appendChild(this.element);
+ }
+ }
+ this.element.wrapper = this;
+ if(!this.element.parentNode && $(parentElement)) {
+ $(parentElement).appendChild(this.element);
+ }
+
+ if(!this.element.id) {
+ this.element.id = "ClientUI_Box" + ClientUI_common_box_Box_idGenerator++;
+ }
+ if(!dontUpdateStyles) {
+ this.element.setStyle({overflow: 'hidden'});
+ this.element.setStyle({whiteSpace: 'nowrap'});
+
+ // if the element isn't positioned, make it relative
+ var position = this.element.getStyle('position');
+ if(position != 'absolute' && position != 'fixed'){
+ this.element.setStyle({position: 'relative'});
+ }
+ }
+ },
+
+ setParent: function(newParent) {
+ if(this.element.parentNode) {
+ this.element.parentNode.removeChild(this.element);
+ }
+ if(newParent) {
+ if(newParent.getElement) {
+ newParent = newParent.getElement();
+ }
+ $(newParent).appendChild(this.element);
+ }
+ return this;
+ },
+ getElement: function() {
+ return this.element;
+ },
+ getHeight: function() {
+ if(this.getElement().tagName.toLowerCase() != "body")
+ return Element.getHeight(this.element);
+
+ if (self.innerHeight) { // all except Explorer
+ return self.innerHeight;
+ }
+ else if (document.documentElement && document.documentElement.clientHeight) {
+ // Explorer 6 Strict Mode
+ return document.documentElement.clientHeight;
+ }
+ else if (document.body) { // other Explorers
+ return document.body.clientHeight;
+ }
+ },
+ isModified: false,
+ setHeight: function(newHeight) {
+ if(Validators.IsNumber(newHeight)) {
+ if(newHeight<0) newHeight = 0;
+ newHeight += "px";
+ }
+ this.element.setStyle({height: newHeight});
+ isModified = true;
+ return this;
+ },
+ getWidth: function() {
+ if(this.getElement().tagName.toLowerCase() != "body")
+ return Element.getWidth(this.element);
+
+ if (self.innerHeight) {// all except Explorer
+ return self.innerWidth;
+ }
+ else if (document.documentElement && document.documentElement.clientHeight) {
+ // Explorer 6 Strict Mode
+ return document.documentElement.clientWidth;
+ }
+ else if (document.body) { // other Explorers
+ return document.body.clientWidth;
+ }
+ },
+ setWidth: function(newWidth) {
+ if(Validators.IsNumber(newWidth)) {
+ if(newWidth<0) newWidth = 0;
+ newWidth += "px";
+ }
+ this.element.setStyle({width: newWidth});
+ isModified = true;
+ return this;
+ },
+ moveToX: function(x) {
+ if(Validators.IsNumber(x)) {x += "px";}
+ this.getElement().setStyle({left: x});
+ isModified = true;
+ return this;
+ },
+ moveToY: function(y) {
+ if(Validators.IsNumber(y)) {y += "px";}
+ this.getElement().setStyle({top: y});
+ isModified = true;
+ return this;
+ },
+ moveTo: function(x, y) {
+ this.moveToX(x);
+ this.moveToY(y);
+ return this;
+ },
+ hide: function() {
+ Element.hide(this.element);
+ isModified = true;
+ return this;
+ },
+ show: function() {
+ Element.show(this.element);
+ isModified = true;
+ return this;
+ },
+ updateLayout: function() {
+ isModified = false;
+ return this;
+ },
+ getViewportWidth: function() {
+ if(this.getElement().tagName.toLowerCase() != "body") {
+ var width = 0;
+ if( this.getElement().clientWidth ) {
+ width = this.getElement().clientWidth;
+ }
+ else if( this.getElement().innerWidth ) {
+ width = this.getElement().innerWidth - getScrollerWidth();
+ }
+
+ if(ClientUILib.isGecko) {
+ width -= this.getPadding("lr");
+ }
+ return width;
+ }
+
+ return this.getWidth();
+ },
+ getViewportHeight: function() {
+ if(this.getElement().tagName.toLowerCase() != "body") {
+ var height = 0;
+ if( this.getElement().clientHeight ) {
+ height = this.getElement().clientHeight;
+ }
+ else if( this.getElement().innerHeight ) {
+ height = this.getElement().innerHeight - getScrollerWidth();
+ }
+
+ if(ClientUILib.isGecko) {
+ height -= this.getPadding("tb");
+ }
+ return height;
+ }
+ return this.getHeight();
+ },
+ /**
+ * Gets the width of the border(s) for the specified side(s)
+ * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
+ * passing lr would get the border (l)eft width + the border (r)ight width.
+ * @return {Number} The width of the sides passed added together
+ */
+ getBorderWidth : function(side){
+ return this.getStyles(side, this.borders);
+ },
+
+ /**
+ * Gets the width of the padding(s) for the specified side(s)
+ * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
+ * passing lr would get the padding (l)eft + the padding (r)ight.
+ * @return {Number} The padding of the sides passed added together
+ */
+ getPadding : function(side){
+ return this.getStyles(side, this.paddings);
+ },
+ getStyles : function(sides, styles){
+ var val = 0;
+ for(var i = 0, len = sides.length; i < len; i++){
+ var w = parseInt(this.getElement().getStyle(styles[sides.charAt(i)]), 10);
+ if(!isNaN(w)) val += w;
+ }
+ return val;
+ },
+ makeAbsolute: function(keepPos) {
+ if(keepPos) {
+ Position.absolutize(this.getElement());
+ }
+ else {
+ this.getElement().setStyle({position: 'absolute'});
+ }
+ return this;
+ },
+ getX: function() {
+ return this.getElement().offsetLeft;
+ },
+ getY: function() {
+ return this.getElement().offsetTop;
+ },
+ setStyle: function(style) {
+ this.getElement().setStyle(style);
+ return this;
+ },
+
+ borders: {l: 'border-left-width', r: 'border-right-width', t: 'border-top-width', b: 'border-bottom-width'},
+ paddings: {l: 'padding-left', r: 'padding-right', t: 'padding-top', b: 'padding-bottom'},
+ margins: {l: 'margin-left', r: 'margin-right', t: 'margin-top', b: 'margin-bottom'}
+
+});
+
+var ClientUI_common_box_Box_idGenerator = 0;
Added: trunk/sandbox/scrollable-grid/src/main/javascript/ClientUI/common/box/InlineBox.js
===================================================================
--- trunk/sandbox/scrollable-grid/src/main/javascript/ClientUI/common/box/InlineBox.js (rev 0)
+++ trunk/sandbox/scrollable-grid/src/main/javascript/ClientUI/common/box/InlineBox.js 2007-04-24 15:27:18 UTC (rev 518)
@@ -0,0 +1,45 @@
+/**
+ * InlineBox.js Date created: 6.04.2007
+ * Copyright (c) 2007 Exadel Inc.
+ * @author Denis Morozov <dmorozov(a)exadel.com>
+ */
+ClientUILib.declarePackage("ClientUI.common.box.InlineBox");
+
+ClientUILib.requireClass("ClientUI.common.box.Box");
+
+/**
+ * Base class that wrap work with inline blocks like span
+ */
+ClientUI.common.box.InlineBox = Class.create({
+ CLASSDEF: {
+ name: 'ClientUI.common.box.InlineBox',
+ parent: ClientUI.common.box.Box
+ }
+});
+
+Object.extend(ClientUI.common.box.InlineBox.prototype, {
+
+ initialize: function(element, parentElement, dontUpdateStyles) {
+ if(!element) {
+ element = $(document.createElement("span"));
+ if($(parentElement)) {
+ $(parentElement).appendChild(element);
+ }
+ else {
+ document.body.appendChild(element);
+ }
+ }
+ if(!element.id) {
+ element.id = "ClientUI_InlineBox" + ClientUI_common_box_InlineBox_idGenerator++;
+ }
+
+ ClientUI.common.box.InlineBox.parentClass.constructor().call(this, element, parentElement, dontUpdateStyles);
+
+ // additional styles
+ if(!dontUpdateStyles) {
+ this.element.setStyle({display: 'block'});
+ }
+ }
+});
+
+var ClientUI_common_box_InlineBox_idGenerator = 0;
\ No newline at end of file
Added: trunk/sandbox/scrollable-grid/src/main/javascript/ClientUI/common/box/ScrollableBox.js
===================================================================
--- trunk/sandbox/scrollable-grid/src/main/javascript/ClientUI/common/box/ScrollableBox.js (rev 0)
+++ trunk/sandbox/scrollable-grid/src/main/javascript/ClientUI/common/box/ScrollableBox.js 2007-04-24 15:27:18 UTC (rev 518)
@@ -0,0 +1,139 @@
+/**
+ * ScrollableBox.js Date created: 6.04.2007
+ * Copyright (c) 2007 Exadel Inc.
+ * @author Denis Morozov <dmorozov(a)exadel.com>
+ */
+ClientUILib.declarePackage("ClientUI.common.box.ScrollableBox");
+
+ClientUILib.requireClass("ClientUI.common.box.Box");
+ClientUILib.requireClass("ClientUI.common.utils.CustomEvent");
+
+/**
+ * This class target to manage scrollable box object.
+ */
+ClientUI.common.box.ScrollableBox = Class.create({
+ CLASSDEF: {
+ name: 'ClientUI.common.box.ScrollableBox',
+ parent: ClientUI.common.box.Box
+ }
+
+});
+
+Object.extend(ClientUI.common.box.ScrollableBox.prototype, {
+
+ // Custom events
+ /**
+ * Occured when content scrolled in horizontal
+ */
+ eventHScroll: {},
+ /**
+ * Occured when content scrolled in vertical
+ */
+ eventVScroll: {},
+
+ //Constructor
+ initialize: function(element, parentElement) {
+ ClientUI.common.box.ScrollableBox.parentClass.constructor().call(this, element, parentElement);
+ this.element.setStyle({overflow: 'auto'});
+
+ // Create custom event producers
+ this.eventHScroll = new ClientUI.common.utils.CustomEvent('OnHScroll');
+ this.eventVScroll = new ClientUI.common.utils.CustomEvent('OnVScroll');
+
+ this.eventOnScroll = this.scrollContent.bindAsEventListener(this);
+ Event.observe(this.element, 'scroll', this.eventOnScroll);
+ },
+ scrollContent: function(event) {
+ this.updateScrollPos();
+ },
+ updateScrollPos: function() {
+ this.timer = null;
+
+ // process horizontal scrolling
+ if(this.scrollLeft!==this.getViewportScrollX()) {
+ this.scrollLeft = this.getViewportScrollX();
+ this.eventHScroll.fire(this.getViewportScrollX());
+ }
+
+ // process vertical scrolling
+ if(this.scrollTop!==this.getViewportScrollY()) {
+ this.scrollTop = this.getViewportScrollY();
+ this.eventVScroll.fire(this.getViewportScrollY());
+ }
+ },
+ updateLayout: function() {
+ // NOTE: not implemented in this class
+ ClientUI.common.box.ScrollableBox.parentClass.method("updateLayout").call(this);
+ ClientUILib.log(ClientUILogger.INFO, "ScrollableBox::updateLayout");
+ },
+ getViewportScrollX: function() {
+ var scrollX = 0;
+ if( this.getElement().scrollLeft ) {
+ scrollX = this.getElement().scrollLeft;
+ }
+ else if( this.getElement().pageXOffset ) {
+ scrollX = this.getElement().pageXOffset;
+ }
+ else if( this.getElement().scrollX ) {
+ scrollX = this.getElement().scrollX;
+ }
+ return scrollX;
+ },
+ getViewportScrollY: function() {
+ var scrollY = 0;
+ if( this.getElement().scrollTop ) {
+ scrollY = this.getElement().scrollTop;
+ }
+ else if( this.getElement().pageYOffset ) {
+ scrollY = this.getElement().pageYOffset;
+ }
+ else if( this.getElement().scrollY ) {
+ scrollY = this.getElement().scrollY;
+ }
+ return scrollY;
+ },
+ getScrollerWidth: function() {
+ if(this.scrollerWidth && this.scrollerWidth > 0)
+ return this.scrollerWidth;
+
+ var scr = null;
+ var inn = null;
+ var wNoScroll = 0;
+ var wScroll = 0;
+
+ // Outer scrolling div
+ scr = document.createElement('div');
+ scr.style.position = 'absolute';
+ scr.style.top = '-1000px';
+ scr.style.left = '-1000px';
+ scr.style.width = '100px';
+ scr.style.height = '50px';
+ // Start with no scrollbar
+ scr.style.overflow = 'hidden';
+
+ // Inner content div
+ inn = document.createElement('div');
+ inn.style.width = '100%';
+ inn.style.height = '200px';
+
+ // Put the inner div in the scrolling div
+ scr.appendChild(inn);
+ // Append the scrolling div to the doc
+ document.body.appendChild(scr);
+
+ // Width of the inner div sans scrollbar
+ wNoScroll = inn.offsetWidth;
+ // Add the scrollbar
+ scr.style.overflow = 'auto';
+ // Width of the inner div width scrollbar
+ wScroll = inn.offsetWidth;
+
+ // Remove the scrolling div from the doc
+ document.body.removeChild(
+ document.body.lastChild);
+
+ // Pixel width of the scroller
+ this.scrollerWidth = (wNoScroll - wScroll);
+ return this.scrollerWidth || 0;
+ }
+})
\ No newline at end of file
Added: trunk/sandbox/scrollable-grid/src/main/javascript/ClientUI/common/box/Substrate.js
===================================================================
--- trunk/sandbox/scrollable-grid/src/main/javascript/ClientUI/common/box/Substrate.js (rev 0)
+++ trunk/sandbox/scrollable-grid/src/main/javascript/ClientUI/common/box/Substrate.js 2007-04-24 15:27:18 UTC (rev 518)
@@ -0,0 +1,39 @@
+/**
+ * Substrate.js Date created: 21.04.2007
+ * Copyright (c) 2007 Exadel Inc.
+ * @author Denis Morozov <dmorozov(a)exadel.com>
+ */
+ClientUILib.declarePackage("ClientUI.common.box.Substrate");
+
+ClientUILib.requireClass("ClientUI.common.box.Box");
+
+/**
+ * Base class that wrap work with inline blocks like span
+ */
+ClientUI.common.box.Substrate = Class.create({
+ CLASSDEF: {
+ name: 'ClientUI.common.box.Substrate',
+ parent: ClientUI.common.box.Box
+ }
+
+});
+
+Object.extend(ClientUI.common.box.Substrate.prototype, {
+
+ initialize: function(element, parentElement, dontUpdateStyles) {
+ if(!element) {
+ var fakeElement = $(document.createElement("div"));
+ fakeElement.innerHTML = '<iframe id="'+'ClientUI_Substrate' + (ClientUI_common_box_Substrate_idGenerator++) +'" src="" scrolling="no" frameborder="0" style="filter:Alpha(opacity=0);position:absolute;top:0px;left:0px;display:block"></iframe>';
+ element = $(fakeElement.getElementsByTagName("iframe")[0]);
+ fakeElement.removeChild(element);
+ }
+
+ ClientUI.common.box.InlineBox.parentClass.constructor().call(this, element, parentElement, dontUpdateStyles);
+
+ // additional styles
+ if(!dontUpdateStyles) {
+ }
+ }
+});
+
+var ClientUI_common_box_Substrate_idGenerator = 0;
\ No newline at end of file
Added: trunk/sandbox/scrollable-grid/src/main/javascript/ClientUI/common/utils/CustomEvent.js
===================================================================
--- trunk/sandbox/scrollable-grid/src/main/javascript/ClientUI/common/utils/CustomEvent.js (rev 0)
+++ trunk/sandbox/scrollable-grid/src/main/javascript/ClientUI/common/utils/CustomEvent.js 2007-04-24 15:27:18 UTC (rev 518)
@@ -0,0 +1,104 @@
+/**
+ * CustomEvent.js Date created: 6.04.2007
+ * Copyright (c) 2007 Exadel Inc.
+ * @author Denis Morozov <dmorozov(a)exadel.com>
+ */
+ClientUILib.declarePackage("ClientUI.common.utils.CustomEvent");
+
+ClientUI.common.utils.CustomEvent = Class.create({
+ CLASSDEF: {
+ name: 'ClientUI.common.utils.CustomEvent'
+ }
+
+});
+
+Object.extend(ClientUI.common.utils.CustomEvent.prototype, {
+ _eventName: 'undefined',
+ _id: -1,
+
+ // Constructor
+ initialize: function(event) {
+ this._eventName = event;
+ // WARNING: If too many events will be in system with dynamic
+ // observation/stop observation than integer idGenerator can be overflowed
+ this._id = ClientUI_common_utils_CustomEvent_idGenerator++;
+ },
+ getName: function() {
+ return this._eventName;
+ },
+ getId: function() {
+ return this._id;
+ },
+
+ // Fire this event and notifies the subscribers.
+ fire: function() {
+ var len = Event.subscribers.length;
+ if (!len) {
+ return true;
+ }
+
+ var id = this.getId();
+ var subscribers = Event.subscribers;
+ var subscribersToNotify = Event.subscribers.findAll(
+ function(subscriber) {
+ return subscriber.event.getId()===id;
+ });
+
+ var args = $A(arguments);
+ subscribersToNotify.each(function(subscriber) {
+ subscriber.callback.apply(subscriber.callback, args);
+ });
+ }
+});
+
+Event._observe = Event.observe;
+Event.observe = function( element, name, observer, useCapture ) {
+ if(element && element.getName && element.getId) {
+ var customEvent = element;
+ if (!this.subscribers) {
+ this.subscribers = [];
+ }
+
+ this.subscribers.push({
+ event: customEvent,
+ desc: name,
+ callback: observer
+ });
+ }
+ else {
+ Event._observe(element, name, observer, useCapture);
+ }
+};
+
+Event._stopObserving = Event.stopObserving;
+Event.stopObserving = function( element, name, observer, useCapture ) {
+ if(element && element.getName && element.getId) {
+ var customEvent = element;
+ if (this.subscribers && this.subscribers.length && this.subscribers.length!==0) {
+ var id = customEvent.getId();
+ this.subscribers = this.subscribers.select(
+ function(subscriber) {
+ return subscriber.event.getId()!==id;
+ });
+ }
+ }
+ else {
+ Event._stopObserving(element, name, observer, useCapture);
+ }
+};
+
+Event._unloadCache = Event.unloadCache;
+Event.unloadCache = function() {
+ if (Event.subscribers) {
+ for (var i = 0, length = Event.subscribers.length; i < length; i++) {
+ Event.stopObserving.apply(this, Event.subscribers[i]);
+ Event.subscribers[i][0] = null;
+ }
+ Event.subscribers = false;
+ }
+ Event._unloadCache();
+};
+
+var ClientUI_common_utils_CustomEvent_idGenerator = 0;
+
+
\ No newline at end of file
Added: trunk/sandbox/scrollable-grid/src/main/javascript/ClientUI/common/utils/StringBuilder.js
===================================================================
--- trunk/sandbox/scrollable-grid/src/main/javascript/ClientUI/common/utils/StringBuilder.js (rev 0)
+++ trunk/sandbox/scrollable-grid/src/main/javascript/ClientUI/common/utils/StringBuilder.js 2007-04-24 15:27:18 UTC (rev 518)
@@ -0,0 +1,64 @@
+/*
+ * TODO: Copyright (c) 2007 Denis Morozov <dmorozov(a)exadel.com>
+ *
+ * ...
+ */
+ClientUILib.declarePackage("ClientUI.common.utils.StringBuilder");
+
+/*
+/* sbuilder.js - Helper class to improve strings concatenation perfomance
+ * by Denis Morozov <dmorozov(a)exadel.com> distributed under the BSD license.
+ *
+ * Usage:
+ * var sb = new StringBuilder();
+ * sb.append("String 1").append("String 2");
+ * sb.append("String 3");
+ * var str = sb.toString();
+ */
+StringBuilder = Class.create({
+ CLASSDEF: {
+ name: 'StringBuilder'
+ }
+
+});
+
+Object.extend(StringBuilder.prototype, {
+ length: 0,
+
+ // private
+ _current: 0,
+ _parts: [],
+ _string: null, // used to cache the string
+
+ initialize: function(str) {
+ this._string = null;
+ this._current = 0;
+ this._parts = [];
+ this.length = 0;
+
+ if(str != null)
+ this.append(str);
+ },
+ append: function (str) {
+ // append argument
+ //this.length += (this._parts[this._current++] = String(str)).length;
+ this._parts.push(String(str));
+
+ // reset cache
+ this._string = null;
+ return this;
+ },
+ toString: function () {
+ if (this._string != null)
+ return this._string;
+
+ var s = this._parts.join("");
+ this._parts = [s];
+ this._current = 1;
+ this.length = s.length;
+
+ return this._string = s;
+ }
+})
+
+
Added: trunk/sandbox/scrollable-grid/src/main/javascript/ClientUI/common/utils/Validators.js
===================================================================
--- trunk/sandbox/scrollable-grid/src/main/javascript/ClientUI/common/utils/Validators.js (rev 0)
+++ trunk/sandbox/scrollable-grid/src/main/javascript/ClientUI/common/utils/Validators.js 2007-04-24 15:27:18 UTC (rev 518)
@@ -0,0 +1,122 @@
+/**
+ * Validators.js Date created: 14.04.2007
+ * Copyright (c) 2007 Exadel Inc.
+ * @author Denis Morozov <dmorozov(a)exadel.com>
+ */
+
+var Validators = {
+ /**
+ * Internet Explorer holds references to objects that are not actually javascript objects. So if we use the
+ * objects in javascript it will give error. But the typeof operator identifies them as javascript objects( problem!!!).
+ * Here we can use the isIEObject() function to identify those objects.
+ */
+ isIEObject: function(a) {
+ return this.isObject(a) && typeof a.constructor != 'function';
+ },
+
+ /**
+ * This function returns true if a is an array, meaning that it was produced by the Array constructor or by
+ * the [ ] array literal notation.
+ */
+ isArray: function(a) {
+ return this.isObject(a) && a.constructor == Array;
+ },
+
+ /**
+ * This function returns true if a is one of the Boolean values, true or false.
+ */
+ isBoolean: function(a) {
+ return typeof a == 'boolean';
+ },
+
+ getBoolean: function(val, defVal) {
+ if(this.isBoolean(val))
+ return val;
+ if(val == "true") return true;
+ else if(val == "false") return false;
+
+ return defVal;
+ },
+
+ /**
+ * This function returns true if a is an object or array or function containing no enumerable members.
+ */
+ isEmpty: function(o) {
+ if (this.isObject(o)) {
+ for (var i in o) {
+ return false;
+ }
+ }
+ else if(this.isString(o) && o.length > 0) {
+ return false;
+ }
+
+ return !this.IsNumber(o);
+ },
+
+ /**
+ * This function returns true if a is a function. Beware that some native functions in IE were made to look
+ * like objects instead of functions. This function does not detect that.Netscape is better behaved in this regard.
+ */
+ isFunction: function(a) {
+ return typeof a == 'function';
+ },
+
+ /**
+ * This function returns true if a is the null value.
+ */
+ isNull: function(a) {
+ return typeof a == 'object' && !a;
+ },
+
+ /**
+ * This function returns true if <code>data</code> is a finite number. It returns false if <code>data</code> is NaN or Infinite.
+ */
+ IsNumber: function(data) {
+ if(typeof data == 'number' && isFinite(data)) {
+ return true;
+ }
+
+ // if it is a string that contains a number
+ var re = /(^-?[1-9](\d{1,2}(\,\d{3})*|\d*)|^0{1})$/;
+ if ( re.test(data) ) {
+ return true;
+ }
+ return false;
+ },
+ IsFormattedNumber: function(data) {
+ // Regular expression should match number with commas or not
+ //1. ^-? <-- '-' is optional at the beginning
+ //2. \d{1,3} <-- with or without comma, first 3 digits
+ //3. \d{1,3}(\,\d{3})* <-- with comma, at least one digit with max of three before repeating like ',ddd'
+ //4. \d+ <-- without comma, match any number of integer(shouldn't be though)
+ var re = /^-?(\d{1,3}|\d{1,3}(\,\d{3})*|\d*)$/g;
+ if ( ! re.test(data) ) {
+ return false;
+ }
+ return true;
+ },
+
+ /**
+ * This function returns true if a is an object, array, or function. It returns false if a is a string,
+ * number, Boolean, null, or undefined.
+ */
+ isObject: function(a) {
+ return (typeof a == 'object' && !!a) || this.isFunction(a);
+ },
+
+ /**
+ * This function returns true if a is a string.
+ */
+ isString: function(a) {
+ return typeof a == 'string';
+ },
+
+ /**
+ * This function returns true if a is the undefined value. You can get the undefined value from an uninitialized
+ * variable or from an object's missing member.
+ */
+ isUndefined: function(a) {
+ return typeof a == 'undefined';
+ }
+};
\ No newline at end of file
Added: trunk/sandbox/scrollable-grid/src/main/javascript/ClientUI/controls/grid/ArrayDataModel.js
===================================================================
--- trunk/sandbox/scrollable-grid/src/main/javascript/ClientUI/controls/grid/ArrayDataModel.js (rev 0)
+++ trunk/sandbox/scrollable-grid/src/main/javascript/ClientUI/controls/grid/ArrayDataModel.js 2007-04-24 15:27:18 UTC (rev 518)
@@ -0,0 +1,39 @@
+/*
+ * TODO: Copyright (c) 2007 Denis Morozov <dmorozov(a)exadel.com>
+ *
+ * ...
+ */
+ClientUILib.declarePackage("ClientUI.controls.grid.ArrayDataModel");
+
+ClientUILib.requireClass("ClientUI.controls.grid.DataModel");
+/*
+ * ArrayDataModel.js - Array datamodel for grid control
+ * by Denis Morozov <dmorozov(a)exadel.com> distributed under the BSD license.
+ *
+ */
+ClientUI.controls.grid.ArrayDataModel = Class.create({
+ CLASSDEF: {
+ name: 'ClientUI.controls.grid.ArrayDataModel',
+ parent: ClientUI.controls.grid.DataModel
+ }
+
+});
+
+Object.extend(ClientUI.controls.grid.ArrayDataModel.prototype, {
+ initialize: function(data) {
+ this.parentClass().constructor().call(this);
+ this.data = $A(data || []);
+ },
+ getRow: function(index) {
+ return this.data[index];
+ },
+ getRows: function(indexFrom, indexTo) {
+ return $A(this.data.slice(indexFrom, indexTo));
+ },
+ getCount: function() {
+ return this.data.length;
+ },
+ getRequestDelay: function() {
+ return 50;
+ }
+})
\ No newline at end of file
Added: trunk/sandbox/scrollable-grid/src/main/javascript/ClientUI/controls/grid/CellsStrip.js
===================================================================
--- trunk/sandbox/scrollable-grid/src/main/javascript/ClientUI/controls/grid/CellsStrip.js (rev 0)
+++ trunk/sandbox/scrollable-grid/src/main/javascript/ClientUI/controls/grid/CellsStrip.js 2007-04-24 15:27:18 UTC (rev 518)
@@ -0,0 +1,126 @@
+/**
+ * CellsStrip.js Date created: 6.04.2007
+ * Copyright (c) 2007 Exadel Inc.
+ * @author Denis Morozov <dmorozov(a)exadel.com>
+ */
+ClientUILib.declarePackage("ClientUI.controls.grid.CellsStrip");
+
+ClientUI.controls.grid.CellsStrip = Class.create({
+ CLASSDEF: {
+ name: 'ClientUI.controls.grid.CellsStrip'
+ }
+
+});
+
+Object.extend(ClientUI.controls.grid.CellsStrip.prototype, {
+ columnWidth: 0,
+ basePos: 0,
+ currOffset: 0,
+
+ initialize: function(options) {
+ this._hash = [];
+ this.columnWidth = 0;
+ this.basePos = 0;
+
+ if(options) {
+ Object.extend(this, options);
+ }
+ },
+
+ length: function() {
+ return this._hash.length;
+ },
+
+ add: function(key, value) {
+ value.key = key;
+ this._hash.push(value);
+ },
+
+ remove: function(key) {
+ var count = this._hash.length;
+ for(var i=0; i<count; i++) {
+ if(this._hash[i].key == key) {
+ this._hash.slice(i, i);
+ break;
+ }
+ }
+ },
+
+ // set cells offset
+ setOffset: function(offset, updateBasePos, silent) {
+ if(!silent) {
+ var basePos = this.basePos;
+ this._hash.each(function(item){
+ item.setOffset(basePos + offset);
+ });
+ }
+
+ this.currOffset = offset;
+ if(updateBasePos) {
+ this.basePos += offset;
+ this.currOffset = 0;
+ }
+ },
+ // set cells width
+ setWidth: function(newWidth, silent) {
+ if(!silent) {
+ this._hash.each(function(item){
+ item.setWidth(newWidth);
+ });
+ }
+ this.columnWidth = newWidth;
+ },
+
+ getWidth: function() {
+ return this.columnWidth;
+ },
+
+ getOffset: function() {
+ return this.currOffset;
+ }
+});
+
+ClientUI.controls.grid.ColumnCell = Class.create({
+ CLASSDEF: {
+ name: 'ClientUI.controls.grid.ColumnCell'
+ },
+ initialize: function(cellObj, parentStrip) {
+ this.cellObj = new ClientUI.common.box.Box(cellObj, null, true);
+ this.parentStrip = parentStrip;
+ },
+
+ // shift column cell in horizontal
+ setOffset: function(offset, updateBasePos) {
+ var newOffset = offset;
+ if(this.separator) {
+ newOffset += this.parentStrip.getWidth() - this.cellObj.getWidth()/2 - 1;
+ }
+ this.cellObj.moveToX(newOffset);
+ },
+
+ // set column width
+ setWidth: function(newWidth) {
+ if(!this.separator) {
+ this.cellObj.setWidth(newWidth);
+ if(this.cellObj.getElement().childNodes.length > 0) {
+ var childs = $A(this.cellObj.getElement().childNodes);
+
+ var fixedWidth = newWidth;
+ if(ClientUILib.isGecko) {
+ var oldElement = this.cellObj.getElement();
+ var i = 0;
+ while(i<childs.length && !childs[i].tagName) i++;
+ if(i<childs.length) {
+ this.cellObj.element = childs[i];
+ fixedWidth -= this.cellObj.getBorderWidth("lr") + this.cellObj.getPadding("lr");
+ $(childs[i]).setStyle({width: fixedWidth + "px"});
+ }
+ this.cellObj.element = oldElement;
+ }
+ }
+ }
+ else {
+ this.setOffset(this.parentStrip.basePos + (newWidth - this.parentStrip.getWidth()));
+ }
+ }
+});
Added: trunk/sandbox/scrollable-grid/src/main/javascript/ClientUI/controls/grid/DataModel.js
===================================================================
--- trunk/sandbox/scrollable-grid/src/main/javascript/ClientUI/controls/grid/DataModel.js (rev 0)
+++ trunk/sandbox/scrollable-grid/src/main/javascript/ClientUI/controls/grid/DataModel.js 2007-04-24 15:27:18 UTC (rev 518)
@@ -0,0 +1,55 @@
+/*
+ * TODO: Copyright (c) 2007 Denis Morozov <dmorozov(a)exadel.com>
+ *
+ * ...
+ */
+ClientUILib.declarePackage("ClientUI.controls.grid.DataModel");
+
+ClientUILib.requireClass("ClientUI.common.utils.CustomEvent");
+
+/*
+ * DataModel.js - Base datamodel class for grid control
+ * by Denis Morozov <dmorozov(a)exadel.com> distributed under the BSD license.
+ *
+ */
+ClientUI.controls.grid.DataModel = Class.create({
+ CLASSDEF: {
+ name: 'ClientUI.controls.grid.DataModel'
+ }
+});
+
+Object.extend(ClientUI.controls.grid.DataModel.prototype, {
+ eventDataReady: {},
+
+ initialize: function() {
+ // constructor
+ this.eventDataReady = new ClientUI.common.utils.CustomEvent('DataModel::OnDataReady');
+ },
+
+ // interface method
+ getRow: function(index) {
+ return [];
+ },
+
+ // interface method
+ getRows: function(indexFrom, indexTo) {
+ return [];
+ },
+
+ // count of all data rows
+ getCount: function() {
+ return 0;
+ },
+
+ // start rows loading
+ loadRows: function(options) {
+ this.eventDataReady.fire(options);
+ },
+
+ // regulate requsts frequency
+ getRequestDelay: function() {
+ return 1000;
+ }
+})
+
+
Added: trunk/sandbox/scrollable-grid/src/main/javascript/ClientUI/controls/grid/DefaultColumnModel.js
===================================================================
--- trunk/sandbox/scrollable-grid/src/main/javascript/ClientUI/controls/grid/DefaultColumnModel.js (rev 0)
+++ trunk/sandbox/scrollable-grid/src/main/javascript/ClientUI/controls/grid/DefaultColumnModel.js 2007-04-24 15:27:18 UTC (rev 518)
@@ -0,0 +1,265 @@
+/*
+ * TODO: Copyright (c) 2007 Denis Morozov <dmorozov(a)exadel.com>
+ *
+ * ...
+ */
+ClientUILib.declarePackage("ClientUI.controls.grid.DefaultColumnModel");
+
+
+ClientUI.controls.grid.DefaultColumnModel = Class.create({
+ CLASSDEF: {
+ name: 'ClientUI.controls.grid.DefaultColumnModel'
+ }
+
+});
+
+Object.extend(ClientUI.controls.grid.DefaultColumnModel.prototype, {
+ initialize: function(config) {
+ this.config = config;
+
+ // default properties
+ this.defaultWidth = 100;
+ this.defaultSortable = false;
+ },
+
+ // generic events arised from columns
+ onWidthChange: function(){},
+ onHeaderChange: function(){},
+ onHiddenChange: function(){},
+
+ // fire event
+ fireWidthChange : function(colIndex, newWidth){
+ this.onWidthChange(this, colIndex, newWidth);
+ },
+
+ fireHeaderChange : function(colIndex, newHeader){
+ this.onHeaderChange(this, colIndex, newHeader);
+ },
+
+ fireHiddenChange : function(colIndex, hidden){
+ this.onHiddenChange(this, colIndex, hidden);
+ },
+
+ /**
+ * Returns the number of columns.
+ * @return {Number}
+ */
+ getColumnCount : function(){
+ return this.config.length;
+ },
+
+ /**
+ * Returns true if the specified column is sortable.
+ * @param {Number} col The column index
+ * @return {Boolean}
+ */
+ isSortable : function(col){
+ if(typeof this.config[col].sortable == 'undefined'){
+ return this.defaultSortable;
+ }
+ return this.config[col].sortable;
+ },
+
+ /**
+ * Interface method - Returns true if the specified column is hidden.
+ * @param {Number} col The column index
+ * @return {Boolean}
+ */
+ isHidden : function(col){
+ return false;
+ },
+
+ /**
+ * Returns the rendering (formatting) function defined for the column.
+ * @param {Number} col The column index
+ * @return {Function}
+ */
+ getRenderer : function(col){
+ if(!this.config[col].renderer){
+ return ClientUI.controls.grid.DefaultColumnModel.defaultRenderer;
+ }
+ return this.config[col].renderer;
+ },
+
+ /**
+ * Sets the rendering (formatting) function for a column.
+ * @param {Number} col The column index
+ * @param {Function} fn
+ */
+ setRenderer : function(col, fn){
+ this.config[col].renderer = fn;
+ },
+
+ /**
+ * Returns the width for the specified column.
+ * @param {Number} col The column index
+ * @return {Number}
+ */
+ getColumnWidth : function(col){
+ return this.config[col].width || this.defaultWidth;
+ },
+
+ /**
+ * Sets the width for a column.
+ * @param {Number} col The column index
+ * @param {Number} width The new width
+ */
+ setColumnWidth : function(col, width, suppressEvent){
+ this.config[col].width = width;
+ this.totalWidth = null;
+ if(!suppressEvent){
+ this.fireWidthChange(col, width);
+ }
+ },
+
+ /**
+ * Returns the total width of all columns.
+ * @param {Boolean} includeHidden True to include hidden column widths
+ * @return {Number}
+ */
+ getTotalWidth : function(includeHidden){
+ if(!this.totalWidth){
+ this.totalWidth = 0;
+ for(var i = 0; i < this.config.length; i++){
+ if(includeHidden || !this.isHidden(i)){
+ this.totalWidth += this.getColumnWidth(i);
+ }
+ }
+ }
+ return this.totalWidth;
+ },
+
+ /**
+ * Returns the header for the specified column.
+ * @param {Number} col The column index
+ * @return {String}
+ */
+ getColumnHeader : function(col){
+ return this.config[col].header;
+ },
+
+ /**
+ * Sets the header for a column.
+ * @param {Number} col The column index
+ * @param {String} header The new header
+ */
+ setColumnHeader : function(col, header){
+ this.config[col].header = header;
+ this.fireHeaderChange(col, header);
+ },
+
+ /**
+ * Returns the tooltip for the specified column.
+ * @param {Number} col The column index
+ * @return {String}
+ */
+ getColumnTooltip : function(col){
+ return this.config[col].tooltip;
+ },
+ /**
+ * Sets the tooltip for a column.
+ * @param {Number} col The column index
+ * @param {String} tooltip The new tooltip
+ */
+ setColumnTooltip : function(col, header){
+ this.config[col].tooltip = tooltip;
+ },
+
+ /**
+ * Returns the dataIndex for the specified column.
+ * @param {Number} col The column index
+ * @return {Number}
+ */
+ getDataIndex : function(col){
+ if(typeof this.config[col].dataIndex != 'number'){
+ return col;
+ }
+ return this.config[col].dataIndex;
+ },
+
+ /**
+ * Sets the dataIndex for a column.
+ * @param {Number} col The column index
+ * @param {Number} dataIndex The new dataIndex
+ */
+ setDataIndex : function(col, dataIndex){
+ this.config[col].dataIndex = dataIndex;
+ },
+ /**
+ * Returns true if the cell is editable.
+ * @param {Number} colIndex The column index
+ * @param {Number} rowIndex The row index
+ * @return {Boolean}
+ */
+ isCellEditable : function(colIndex, rowIndex){
+ return this.config[colIndex].editable || (typeof this.config[colIndex].editable == 'undefined' && this.config[colIndex].editor);
+ },
+
+ /**
+ * Returns the editor defined for the cell/column.
+ * @param {Number} colIndex The column index
+ * @param {Number} rowIndex The row index
+ * @return {Object}
+ */
+ getCellEditor : function(colIndex, rowIndex){
+ return this.config[colIndex].editor;
+ },
+
+ /**
+ * Sets if a column is editable.
+ * @param {Number} col The column index
+ * @param {Boolean} editable True if the column is editable
+ */
+ setEditable : function(col, editable){
+ this.config[col].editable = editable;
+ },
+
+ /**
+ * Returns true if the column is hidden.
+ * @param {Number} colIndex The column index
+ * @return {Boolean}
+ */
+ isHidden : function(colIndex){
+ return this.config[colIndex].hidden;
+ },
+
+ /**
+ * Returns true if the column width cannot be changed
+ */
+ isFixed : function(colIndex){
+ return this.config[colIndex].fixed;
+ },
+
+ /**
+ * Returns true if the column cannot be resized
+ * @return {Boolean}
+ */
+ isResizable : function(colIndex){
+ return this.config[colIndex].resizable !== false;
+ },
+ /**
+ * Sets if a column is hidden.
+ * @param {Number} colIndex The column index
+ */
+ setHidden : function(colIndex, hidden){
+ this.config[colIndex].hidden = hidden;
+ this.totalWidth = null;
+ this.fireHiddenChange(colIndex, hidden);
+ },
+
+ /**
+ * Sets the editor for a column.
+ * @param {Number} col The column index
+ * @param {Object} editor The editor object
+ */
+ setEditor : function(col, editor){
+ this.config[col].editor = editor;
+ }
+});
+
+ClientUI.controls.grid.DefaultColumnModel.defaultRenderer = function(value){
+ if(typeof value == 'string' && value.length < 1){
+ return ' ';
+ }
+ return value;
+}
\ No newline at end of file
Added: trunk/sandbox/scrollable-grid/src/main/javascript/ClientUI/controls/grid/Grid.js
===================================================================
--- trunk/sandbox/scrollable-grid/src/main/javascript/ClientUI/controls/grid/Grid.js (rev 0)
+++ trunk/sandbox/scrollable-grid/src/main/javascript/ClientUI/controls/grid/Grid.js 2007-04-24 15:27:18 UTC (rev 518)
@@ -0,0 +1,309 @@
+/**
+ * Grid.js Date created: 6.04.2007
+ * Copyright (c) 2007 Exadel Inc.
+ * @author Denis Morozov <dmorozov(a)exadel.com>
+ */
+ClientUILib.declarePackage("ClientUI.controls.grid.Grid");
+
+ClientUILib.requireClass("ClientUI.common.box.Box");
+ClientUILib.requireClass("ClientUI.controls.grid.GridHeader");
+ClientUILib.requireClass("ClientUI.controls.grid.GridBody");
+ClientUILib.requireClass("ClientUI.controls.grid.GridFooter");
+ClientUILib.requireClass("ClientUI.controls.grid.CellsStrip");
+
+/*
+ * grid.js - Grid library on top of Prototype
+ * by Denis Morozov <dmorozov(a)exadel.com> distributed under the BSD license.
+ *
+ * TODO: description of control
+ *
+ * TODO: usage description
+ * Usage:
+ * <script src="/javascripts/prototype.js" type="text/javascript"></script>
+ * <script src="/javascripts/extend.js" type="text/javascript"></script>
+ * <script src="/javascripts/grid.js" type="text/javascript"></script>
+ * <script type="text/javascript">
+ * // with valid DOM id
+ * var grid = new ClientUI.controls.grid.Grid('id_of_trigger_element', 'id_of_tooltip_to_show_element')
+ *
+ * // with text
+ * var grid = new ClientUI.controls.grid.Grid('id_of_trigger_element', 'a nice description')
+ * </script>
+ */
+ClientUI.controls.grid.Grid = Class.create({
+ CLASSDEF: {
+ name: 'ClientUI.controls.grid.Grid',
+ parent: ClientUI.common.box.Box
+ }
+
+});
+
+Object.extend(ClientUI.controls.grid.Grid.prototype, {
+ // Custom events
+ /**
+ * Occured when content header clicked
+ */
+ eventOnSort: {},
+
+ initialize: function(element, dataModel, templates, options) {
+ ClientUI.controls.grid.Grid.parentClass.constructor().call(this, element);
+ if(!element || !element.id)
+ this.element.id = "ClientUI_Grid" + ClientUI_controls_grid_Grid_idGenerator++;
+
+ this.dataModel = dataModel;
+ this.templates = $A(templates);
+
+ this.eventOnSort = new ClientUI.common.utils.CustomEvent('OnSort');
+
+ // grid options
+ this.options = {
+ showIndexColumn: false,
+ indexColumnWidth: 30
+ };
+ if(options) { Object.extend(this.options, options); }
+
+ this.createControl();
+ },
+ createControl: function() {
+ var grid = this;
+ var layout = new ClientUI.layouts.GridLayoutManager(null, this.getElement());
+ this.layout = layout;
+
+ this.templates.each(function(item) {
+ switch(item.pane) {
+ case GridLayout_Enum.HEADER:
+ var header = new ClientUI.controls.grid.GridHeader($(item.ref), grid);
+ layout.addPane(GridLayout_Enum.HEADER, header);
+ break;
+ case GridLayout_Enum.BODY:
+ var body = new ClientUI.controls.grid.GridBody($(item.ref), grid);
+ layout.addPane(GridLayout_Enum.BODY, body);
+ break;
+ case GridLayout_Enum.FOOTER:
+ var footer = new ClientUI.controls.grid.GridFooter($(item.ref), grid);
+ layout.addPane(GridLayout_Enum.FOOTER, footer);
+ break;
+ }
+ });
+
+ // create cells strips
+ this._columnsStrip = [];
+ var columns = this.getHeader().getColumns();
+ for(var i=0; i<columns.length; i++) {
+ this._columnsStrip[i] = new ClientUI.controls.grid.CellsStrip({
+ columnWidth: columns[i].object.getWidth(),
+ basePos: columns[i].object.getX(),
+ frozen: columns[i].frozen
+ });
+ }
+
+ this._parseRowAndAddToStrips("header", this.getHeader().getRow());
+ if(this.getFooter()) {
+ this._parseRowAndAddToStrips("footer", this.getFooter().getRow());
+ }
+
+ this.currentScrollPos = 0;
+ this.controlCreated = true;
+ this.updateLayout();
+ },
+ updateLayout: function() {
+ if(!this.controlCreated) {
+ return;
+ }
+ ClientUI.controls.grid.Grid.parentClass.method("updateLayout").call(this);
+ if(this.layout) {
+ this.layout.updateLayout();
+ }
+ },
+ getHeader: function() {
+ return this.layout.getPane(GridLayout_Enum.HEADER);
+ },
+ getFooter: function() {
+ return this.layout.getPane(GridLayout_Enum.FOOTER);
+ },
+ getBody: function() {
+ return this.layout.getPane(GridLayout_Enum.BODY);
+ },
+ _getVisibleHeaderControls: function() {
+ var controls = [];
+ var columns = this.getHeader().getColumns();
+ columns.each(function(column){
+ var ctrls = $A(column.body.getElement().getElementsByTagName("select"));
+ ctrls.each(function(ctrl){
+ if(Element.visible(ctrl)) {
+ controls.push(ctrl);
+ }
+ });
+ });
+ return controls;
+ },
+ adjustColumnWidth: function(index, width) {
+ var oldWidth = this.getHeader().getColumns()[index].object.getWidth();
+
+ // 1. set new width
+ this._columnsStrip[index].setWidth(width);
+
+ // Hide controls in IE that flipped in other case
+ var ctrlsIE = [];
+ if(ClientUILib.isIE) {
+ ctrlsIE = this._getVisibleHeaderControls();
+ ctrlsIE.each(function(ctrl){
+ Element.hide(ctrl);
+ });
+ }
+
+ // 2. shift right side columns
+ if(index < this._columnsStrip.length-1) {
+ var count = this._columnsStrip.length;
+ if(this._columnsStrip[index].frozen) {
+ // if current column is frozen, lets find last frozen column index
+ var i=index+1;
+ while(this._columnsStrip[i].frozen && i<count) {
+ i++;
+ }
+ count = i;
+ }
+
+ var offset = width - oldWidth;
+ for(var i=index+1; i<count; i++) {
+ this._columnsStrip[i].setOffset(offset, true);
+ }
+ }
+
+ this.updateLayout();
+
+ if(ClientUILib.isIE) {
+ ctrlsIE.each(function(ctrl){
+ Element.show(ctrl);
+ });
+ }
+ },
+ adjustScrollPosition: function(pos) {
+ if(pos<0) {pos = 0;}
+ this.currentScrollPos = pos;
+ var i=0;
+ while(i<this._columnsStrip.lenth && this._columnsStrip[i].frozen) i++;
+ if(i<this._columnsStrip.length) {
+ while(i<this._columnsStrip.length) {
+ this._columnsStrip[i++].setOffset(pos, false, true);
+ }
+ }
+ this.getHeader().adjustScrollPosition(pos);
+ this.getBody().adjustScrollPosition(pos);
+ if(this.getFooter()) {this.getFooter().adjustScrollPosition(pos);}
+ },
+ loadData: function() {
+ this.getBody().adjustDataPosition(0);
+ },
+ frozeColumn: function(index, froze) {
+ if(index<0 || index>=this.getHeader().getColumns().length)
+ return false;
+ this.getHeader().getColumns()[index].frozen = froze;
+ },
+ setColumnMinWidth: function(index, width) {
+ if(index<0 || index>=this.getHeader().getColumns().length)
+ return false;
+ this.getHeader().getColumns()[index].minWidth = width;
+ return true;
+ },
+ _isSeparator: function(element) {
+ return Element.hasClassName(element, this.getHeader().CLASSDEF.sepStyleClass);
+ },
+ _isCell: function(element) {
+ return element.tagName && element.tagName.toLowerCase()!="iframe";
+ },
+ // helper method parse row of elements and add separately into rows and columns list
+ _parseRowAndAddToStrips: function(id, object) {
+ var i=0, j=0, cells, cell, count=0;
+ if(object.frozen && object.normal) {
+ // process frozen columns
+ cells = object.frozen.getElement().childNodes;
+ count = cells.length;
+ for(i=0, j=0; i<count; i++) {
+ cell = cells[i];
+ if(this._isCell(cell) && !this._isSeparator(cell)) {
+ this._columnsStrip[j].add(id, new ClientUI.controls.grid.ColumnCell(
+ cell,
+ this._columnsStrip[j]));
+ j++;
+ }
+ }
+ var sripIndex = j;
+ for(i=0, j=0; i<count; i++) { // process separators
+ cell = cells[i];
+ if(this._isSeparator(cell)) {
+ var columnCell = new ClientUI.controls.grid.ColumnCell(
+ cell,
+ this._columnsStrip[j]);
+ columnCell.separator = true;
+ this._columnsStrip[j].add(id, columnCell);
+ j++;
+ }
+ }
+
+ // process normal columns
+ i = sripIndex;
+ cells = object.normal.getElement().childNodes;
+ for(j=0; j<cells.length; j++) {
+ cell = cells[j];
+ if(this._isCell(cell) && !this._isSeparator(cell)) {
+ this._columnsStrip[i].add(id, new ClientUI.controls.grid.ColumnCell(
+ cell,
+ this._columnsStrip[i]));
+ i++;
+ }
+ }
+ i = sripIndex;
+ for(j=0; j<cells.length; j++) { // process separators
+ cell = cells[j];
+ if(this._isSeparator(cell)) {
+ var columnCell = new ClientUI.controls.grid.ColumnCell(
+ cell,
+ this._columnsStrip[i]);
+ columnCell.separator = true;
+ this._columnsStrip[i].add(id, columnCell);
+ i++;
+ }
+ }
+ }
+ },
+ _getParsedRowsCount: function() {
+ return this._columnsStrip[0].length();
+ },
+ _removeRowFromStrips: function(id) {
+ this._columnsStrip.each(function(strip){
+ strip.remove(id);
+ });
+ },
+ getColumnScrollX: function(index) {
+ if(index) {
+ return index<this._columnsStrip.length ? this._columnsStrip[index].currOffset : this.currentScrollPos;
+ }
+
+ return this.currentScrollPos;
+ },
+ getColumnsTotalWidth: function() {
+ var totalWidth = 0;
+ this.getHeader().getColumns().each(function(column){
+ totalWidth += column.object.getWidth();
+ });
+
+ return totalWidth;
+ },
+ getColumnsFrozenWidth: function() {
+ var totalWidth = 0;
+ var columns = this.getHeader().getColumns();
+ var i = 0;
+ while(i<columns.length && columns[i].frozen) {
+ totalWidth += columns[i++].object.getWidth();
+ }
+ return totalWidth;
+
+ },
+ invalidate: function(params) {
+ this.getBody().invalidate(params);
+ }
+})
+
+var ClientUI_controls_grid_Grid_idGenerator = 0;
+
Added: trunk/sandbox/scrollable-grid/src/main/javascript/ClientUI/controls/grid/GridBody.js
===================================================================
--- trunk/sandbox/scrollable-grid/src/main/javascript/ClientUI/controls/grid/GridBody.js (rev 0)
+++ trunk/sandbox/scrollable-grid/src/main/javascript/ClientUI/controls/grid/GridBody.js 2007-04-24 15:27:18 UTC (rev 518)
@@ -0,0 +1,738 @@
+/*
+ * TODO: Copyright (c) 2007 Denis Morozov <dmorozov(a)exadel.com>
+ *
+ * ...
+ */
+ClientUILib.declarePackage("ClientUI.controls.grid.GridBody");
+
+ClientUILib.requireClass("ClientUI.common.box.Box");
+
+/*
+ * GridHeader.js - Grid control header pane
+ * TODO: add comments
+ */
+ClientUI.controls.grid.GridBody = Class.create({
+ CLASSDEF: {
+ name: 'ClientUI.controls.grid.GridBody',
+ parent: ClientUI.common.box.Box
+ }
+
+});
+
+Object.extend(ClientUI.controls.grid.GridBody.prototype, {
+ /**
+ * Count of rows can be viewed in the same time in grid
+ */
+ dataVisible: 50,
+
+ /**
+ * Count of rows loaded additianally to dataVisible rows
+ */
+ dataDelta: 5,
+
+ /**
+ * Contains loaded data
+ */
+ dataView: [],
+
+ /**
+ * Pool for rows. Targeted to improve perfomance
+ */
+ rowsPool: [],
+
+ /**
+ * Current data position
+ */
+ currentPos: 0,
+
+ /**
+ * Constructor
+ * @param {Object} template for Grid body row
+ * @param {Object} grid parent grid object
+ */
+ initialize: function(template, grid) {
+ this.grid = grid;
+ ClientUI.controls.grid.GridBody.parentClass.constructor().call(this, null, grid.getElement());
+ this.element.id = this.grid.getElement().id + "_Body";
+
+ // declare event listeners
+ this._eventOnHScroll = this._onContentHScroll.bind(this);
+ this._eventOnVScroll = this._onContentVScroll.bind(this);
+ this._eventOnDataReady = this._onDataReady.bind(this);
+
+ this.createControl(template);
+ this.registerEvents();
+ this.updateLayout();
+ },
+ // event listeners
+ _onContentHScroll: function(xpos) {
+ this.grid.adjustScrollPosition(xpos);
+ },
+ _onContentVScroll: function(ypos) {
+ this.helpObject1.moveToY(this.sizeBox.getHeight()+ this.defaultRowHeight + 5);
+ this.helpObject2.moveToY(this.sizeBox.getHeight()+ this.defaultRowHeight + 5);
+ this.setScrollPos(ypos);
+ this.adjustDataPosition(ypos);
+ },
+ _onDataReady: function(options) {
+ // load rows data
+ var loadRow = this.loadRow.bind(this);
+ var byIndex = options.indexes!==null;
+ var count = options.indexes!==null ? options.indexes.length : (options.ids!==null?options.ids.lenth : 0);
+ var i;
+ for(i=0; i<count; i++) {
+ loadRow(
+ options.indexes!==null ? options.indexes[i] : null,
+ options.ids!==null ? options.ids[i] : null);
+ }
+
+ // This trick to force IE rerender rows
+ if(ClientUILib.isIE && !ClientUILib.isIE7) {
+ this.setScrollPos(this.currentPos);
+ this.adjustScrollPosition(this.grid.getColumnScrollX());
+ }
+ },
+ registerEvents: function() {
+ Event.observe(this.scrollBox.eventHScroll, "grid body hscroll", this._eventOnHScroll);
+ Event.observe(this.scrollBox.eventVScroll, "grid body vscroll", this._eventOnVScroll);
+ Event.observe(this.grid.dataModel.eventDataReady, "grid data is loaded", this._eventOnDataReady);
+ },
+ destroy: function() {
+ Event.stopObserving(this.scrollBox.eventHScroll, "grid body hscroll", this._eventOnHScroll);
+ Event.stopObserving(this.scrollBox.eventVScroll, "grid body vscroll", this._eventOnVScroll);
+ Event.stopObserving(this.grid.dataModel.eventDataReady, "grid data is loaded", this._eventOnDataReady);
+ },
+ createControl: function(template) {
+ // validate template
+ var ch = $(template).firstChild;
+ while(ch) {
+ if(ch.tagName && ch.tagName.toLowerCase()=="table") {
+ this.template = $(ch);
+ break;
+ }
+ ch = ch.nextSibling;
+ }
+
+ template.parentNode.removeChild(template);
+ document.body.appendChild(template);
+
+ var errMsg = "";
+ if(!this.template) {
+ errMsg = "Invalid template specified. GridFooter requires template specified over table element.";
+ ClientUILib.log(ClientUILogger.ERROR, errMsg);
+ throw(errMsg);
+ }
+ if(!this.parseTemplate(this.template)) {
+ errMsg = "Unable to parse template. GridFooter requires template specified over table element with one row.";
+ ClientUILib.log(ClientUILogger.ERROR, errMsg);
+ throw(errMsg);
+ }
+
+ // Remove template
+ document.body.removeChild(template);
+
+ // create scroll box
+ this.scrollBox = new ClientUI.common.box.ScrollableBox(null, this.getElement());
+ this.scrollBox.makeAbsolute();
+ this.contentBox = new ClientUI.common.box.Box(null, this.getElement());
+ this.contentBox.makeAbsolute();
+ this.frozenContentBox = new ClientUI.common.box.Box(null, this.getElement());
+ this.frozenContentBox.makeAbsolute();
+ this.sizeBox = new ClientUI.common.box.Box(null, this.scrollBox.getElement());
+ this.sizeBox.makeAbsolute();
+
+ this.helpObject1 = new ClientUI.common.box.Box($(document.createElement("img")), this.contentBox.getElement());
+ this.helpObject1.setWidth(10);
+ this.helpObject1.setHeight(10);
+ this.helpObject1.makeAbsolute();
+ this.helpObject2 = new ClientUI.common.box.Box($(document.createElement("img")), this.frozenContentBox.getElement());
+ this.helpObject2.setWidth(10);
+ this.helpObject2.setHeight(10);
+ this.helpObject2.makeAbsolute();
+
+ // create row template
+ this._createRowTemplate();
+ this.controlCreated = true;
+ },
+ parseTemplate: function(template) {
+ if(!template || !template.rows || template.rows.length===0) {
+ return false;
+ }
+
+ var columns = [];
+
+ // Get columns information
+ var i = 0;
+ if(this.grid.options.showIndexColumn) {
+ columns[i++] = {
+ value: "$(row)",
+ styleClass: "",
+ id: "",
+ align: "left",
+ valign: "middle",
+ indexRow: true
+ };
+ }
+
+ var cells = $A(template.rows[0].cells);
+ cells.each(function(cell) {
+ columns[i++] = {
+ value: cell.innerHTML,
+ styleClass: cell.className,
+ id: cell.id,
+ align: cell.align,
+ valign: cell.vAlign
+ };
+
+ Element.addClassName(cell, "ClientUI_Grid_BCBody");
+ });
+ this._columns = columns;
+ this.defaultRowHeight = Element.getHeight(template.rows[0].cells[0]);
+ if(ClientUILib.isGecko) {
+ this.defaultRowHeight -= this.getBorderWidth("tb") + this.getPadding("tb");
+ }
+ return true;
+ },
+ getColumns: function() {
+ return this._columns;
+ },
+ setScrollPos: function(pos) {
+ this.contentBox.getElement().scrollTop = pos;
+ this.frozenContentBox.getElement().scrollTop = pos;
+ if(ClientUILib.isIE && !ClientUILib.isIE7) {
+ this.contentBox.getElement().scrollTop = pos;
+ this.frozenContentBox.getElement().scrollTop = pos;
+ }
+ },
+ updateLayout: function() {
+ if(!this.controlCreated || !this.grid.controlCreated) {
+ return;
+ }
+ ClientUI.controls.grid.GridBody.parentClass.method("updateLayout").call(this);
+ if(!this.scrollBox || !this.contentBox || !this.sizeBox) {
+ return;
+ }
+
+ var scrollLeft = this.contentBox.getElement().scrollLeft;
+ var height = this.scrollBox.getViewportHeight();
+ var fixH = this.grid.getFooter() ? this.grid.getFooter().getHeight() : 0;
+ if(fixH > height) fixH = 0;
+ var totalWidth = this.grid.getColumnsTotalWidth();
+ var frozenContentWidth = this.grid.getColumnsFrozenWidth();
+
+ this.scrollBox.moveTo(0, 0);
+ this.sizeBox.moveTo(0, 0);
+ this.frozenContentBox.moveTo(0, 0);
+ this.contentBox.moveTo(frozenContentWidth, 0);
+
+ this.sizeBox.setWidth(totalWidth);
+ this.sizeBox.setHeight(this.defaultRowHeight * this.grid.dataModel.getCount() + fixH);
+ this.helpObject1.moveToY(this.sizeBox.getHeight()+ this.defaultRowHeight + 5);
+ this.helpObject2.moveToY(this.sizeBox.getHeight()+ this.defaultRowHeight + 5);
+
+ // NOTE: this needed to force this.scrollBox update scrolled area
+ this.scrollBox.setWidth(this.getWidth()+1);
+ this.scrollBox.setHeight(this.getHeight()+1);
+ this.scrollBox.setWidth(this.getWidth());
+ this.scrollBox.setHeight(this.getHeight());
+
+ this.contentBox.setWidth(this.scrollBox.getViewportWidth()-frozenContentWidth);
+ this.contentBox.setHeight(height - fixH);
+ this.frozenContentBox.setWidth(frozenContentWidth);
+ this.frozenContentBox.setHeight(height - fixH);
+
+ var scrollPos = Math.min(totalWidth - frozenContentWidth - this.contentBox.getWidth(), scrollLeft);
+ this.grid.adjustScrollPosition(scrollPos);
+
+ this.dataVisible = parseInt(this.contentBox.getHeight() / this.defaultRowHeight, 10) + 1;
+ if(height > 0) {
+ this.adjustDataPosition(this.currentPos);
+ }
+ },
+ adjustScrollPosition: function(pos) {
+ this.contentBox.getElement().scrollLeft = pos;
+ },
+ getScrollXPosition: function() {
+ return this.contentBox.getElement().scrollLeft;
+ },
+ getScrollYPosition: function() {
+ return this.contentBox.getElement().scrollTop;
+ },
+ _createRowTemplate: function() {
+ var headerRow = new ClientUI.common.box.InlineBox(null, this.contentBox.getElement());
+ headerRow.getElement().addClassName("ClientUI_Grid_BR");
+ headerRow.setWidth(10000);
+ headerRow.setHeight(this.defaultRowHeight);
+ headerRow.makeAbsolute();
+ headerRow.moveTo(0, -100);
+ headerRow.rowindex = -1;
+
+ var headerFrozenRow = new ClientUI.common.box.InlineBox(headerRow.getElement().cloneNode(true));
+ headerFrozenRow.setParent(this.frozenContentBox.getElement());
+
+ var frozenContentBox = this.frozenContentBox;
+ var rowClientHeight = headerRow.getViewportHeight();
+ var bodyWidthFix = 0;
+ var bodyHeightFix = 0;
+
+ var columnZIndex = this.grid.getHeader().getColumns().length*3 + 10;
+ var calculateFixes = true;
+ var defaultWidth = 0;
+ var defaultWidthFrozen = 0;
+ var columns = this._columns;
+ var i = 0;
+
+ this.grid.getHeader().getColumns().each(function(headerColumnDesc) {
+
+ var columnDesc = columns[i++];
+ var width = headerColumnDesc.object.getWidth();
+ var height = rowClientHeight;
+
+ var parent = headerColumnDesc.frozen ? headerFrozenRow.getElement() : headerRow.getElement();
+ var col = new ClientUI.common.box.InlineBox(null, parent);
+ col.makeAbsolute();
+ var styles = columnDesc.indexRow ? "ClientUI_Grid_BCIndex" : "ClientUI_Grid_BC";
+ col.getElement().addClassName(styles);
+
+ if(columnDesc.indexRow) {
+ height -= col.getBorderWidth("tb");
+ //height = height + "px !important";
+ }
+
+ col.getElement().setStyle({zIndex: columnZIndex});
+ columnZIndex -= 3;
+ col.getElement().columnindex = i-1;
+ col.getElement().hidefocus = "true";
+ col.getElement().tabindex="0";
+ col.setWidth(width);
+ col.setHeight(height);
+
+ if(!headerColumnDesc.frozen) {
+ col.moveToX(defaultWidth);
+ defaultWidth += width;
+ }
+ else {
+ col.moveToX(defaultWidthFrozen);
+ defaultWidthFrozen += width;
+ }
+
+ var colBody = new ClientUI.common.box.InlineBox(null, col.getElement());
+ if(!Validators.isEmpty(columnDesc.styleClass)) {
+ colBody.getElement().addClassName(columnDesc.styleClass);
+ }
+ colBody.getElement().addClassName("ClientUI_Grid_BCBody");
+ if(calculateFixes && ClientUILib.isGecko) {
+ bodyWidthFix = colBody.getBorderWidth("lr") + colBody.getPadding("lr");
+ bodyHeightFix = colBody.getBorderWidth("tb") + colBody.getPadding("tb");
+ calculateFixes = false;
+ }
+ colBody.setWidth(width - bodyWidthFix);
+ colBody.setHeight(height - bodyHeightFix);
+ if(!Validators.isEmpty(columnDesc.valign)) {
+ colBody.getElement().setStyle({verticalAlign: columnDesc.valign});
+ }
+ if(!Validators.isEmpty(columnDesc.align)) {
+ colBody.getElement().setStyle({textAlign: columnDesc.align});
+ }
+ });
+
+ //if(ClientUILib.isGecko) {
+ headerRow.hide();
+ //}
+ this.headerRowTemplate = headerRow;
+ this.headerFrozenRowTemplate = headerFrozenRow;
+ },
+ _getRowDesc: function(parent, idPrefix, headerRow, headerFrozenRow) {
+ var rowDesc = {
+ id: headerRow.getElement().id,
+ idprefix: idPrefix,
+ parent: parent,
+ frozen: headerFrozenRow,
+ normal: headerRow,
+ moveToY: function(y) {
+ this.frozen.moveToY(y);
+ this.normal.moveToY(y);
+ },
+ getId: function() {
+ return this.id;
+ },
+ setId: function(id) {
+ this.id = id;
+ this.frozen.getElement().id = id;
+ this.normal.getElement().id = id;
+
+ var cellObj, cB;
+ var i, index = 0;
+ var cnt = this.frozen.getElement().childNodes.length;
+ for(i=0; i<cnt; i++) {
+ cellObj = this.frozen.getElement().childNodes[i];
+ cellObj.id = "c_"+ this.rowindex +"_" + index++;
+ cB = document.getElementsByClassName("ClientUI_Grid_BCBody", cellObj);
+ cB[0].id = "b"+ cellObj.id;
+
+ }
+ cnt = this.normal.getElement().childNodes.length;
+ for(i=0; i<cnt; i++) {
+ cellObj = this.normal.getElement().childNodes[i];
+ cellObj.id = "c_"+ this.rowindex +"_" + index++;
+ cB = document.getElementsByClassName("ClientUI_Grid_BCBody", cellObj);
+ cB[0].id = "b"+ cellObj.id;
+ }
+ },
+ setRowIndex: function(index) {
+ this.rowindex = index;
+ this.frozen.getElement().rowindex = index;
+ this.normal.getElement().rowindex = index;
+ this.setId(this.idprefix + this.rowindex);
+ },
+ setRowClass: function(isOdd) {
+ if(isOdd) {
+ this.frozen.getElement().removeClassName("ClientUI_Grid_BREven");
+ this.normal.getElement().removeClassName("ClientUI_Grid_BREven");
+ this.frozen.getElement().addClassName("ClientUI_Grid_BROdd");
+ this.normal.getElement().addClassName("ClientUI_Grid_BROdd");
+ }
+ else {
+ this.frozen.getElement().removeClassName("ClientUI_Grid_BROdd");
+ this.normal.getElement().removeClassName("ClientUI_Grid_BROdd");
+ this.frozen.getElement().addClassName("ClientUI_Grid_BREven");
+ this.normal.getElement().addClassName("ClientUI_Grid_BREven");
+ }
+ },
+ setCellValue: function(index, newValue) {
+ var i = index;
+ var cnt1 = this.frozen.getElement().childNodes.length;
+ if(i < cnt1) {
+ var cellObj = this.frozen.getElement().childNodes[i];
+ Element.update(cellObj.firstChild, newValue);
+ return true;
+ }
+ i -= cnt1;
+ var cellObj = this.normal.getElement().childNodes[i];
+ Element.update(cellObj.firstChild, newValue);
+ return true;
+ },
+ show: function() {
+ this.frozen.show();
+ this.normal.show();
+ },
+ showWaitData: function(show) {
+ // process frozen
+ var cells = this.frozen.getElement().childNodes;
+ var i = 0, startIndex = 0;
+ if(this.parent.grid.options.showIndexColumn) {
+ startIndex = 1;
+ this.setCellValue(0, ""+this.rowindex);
+ }
+ var method = !show ? Element.show : Element.hide;
+ for(i=startIndex;i<cells.length; i++) {
+ method(cells[i]);
+ }
+
+ //process normal
+ cells = this.normal.getElement().childNodes;
+ for(i=0;i<cells.length; i++) {
+ method(cells[i]);
+ }
+ },
+ hide: function() {
+ this.frozen.hide();
+ this.normal.hide();
+ },
+ showEmpty: function() {
+ this.moveToY(this.parent.defaultRowHeight * this.rowindex);
+ if(!(ClientUILib.isIE && !ClientUILib.isIE7)) {
+ this.setRowClass(this.rowindex%2 ? false : true);
+ this.show();
+ this.showWaitData(true);
+ }
+ },
+ showNormal: function() {
+ this.show();
+ if(ClientUILib.isIE && !ClientUILib.isIE7) {
+ this.setRowClass(this.rowindex%2 ? false : true);
+ if(this.parent.grid.options.showIndexColumn) {
+ this.setCellValue(0, ""+this.rowindex);
+ }
+ }
+ else {
+ this.showWaitData(false);
+ }
+ },
+ loadRowData: function(row, index, rowData) {
+
+ // replace data patterns in content with real data from row
+ var count = this.parent.grid.getHeader().getColumns().length;
+ var columns = this.parent.getColumns();
+ var i = this.parent.grid.options.showIndexColumn ? 1 : 0;
+ for(; i<count; i++) {
+ var value = this.parent.parseExpression(columns[i].value, rowData, {
+ row: index,
+ cid: row.getId() + ":" + i,
+ rid: row.getId()
+ });
+ this.setCellValue(i, value);
+ }
+
+ this.showNormal();
+ return true;
+ },
+ getCellsToUpdate: function() {
+ var fcs = $A(document.getElementsByClassName("ClientUI_Grid_BCBody", this.frozen.getElement()));
+ var ncs = $A(document.getElementsByClassName("ClientUI_Grid_BCBody", this.normal.getElement()));
+ var ids = [];
+ fcs.each(function (cell){ids.push(cell.id);});
+ ncs.each(function (cell){ids.push(cell.id);});
+ return ids;
+ }
+ };
+
+ return rowDesc;
+ },
+ createRow: function() {
+ var row = null;
+ var rowFrozen = null;
+ if(this.templateRow) { // use existing template to inherit cell's width & offset
+ row = this.templateRow.normal.getElement().cloneNode(true);
+ rowFrozen = this.templateRow.frozen.getElement().cloneNode(true);
+ }
+ else { // first time
+ row = this.headerRowTemplate.getElement().cloneNode(true);
+ rowFrozen = this.headerFrozenRowTemplate.getElement().cloneNode(true);
+ }
+
+ var headerRow = new ClientUI.common.box.InlineBox(row, this.contentBox.getElement(), true);
+ headerRow.setParent(this.contentBox.getElement());
+ var headerFrozenRow = new ClientUI.common.box.InlineBox(rowFrozen, this.frozenContentBox.getElement(), true);
+ headerFrozenRow.setParent(this.frozenContentBox.getElement());
+
+ var rowDesc = this._getRowDesc(this, this.getElement().id + "BR", headerRow, headerFrozenRow);
+
+ // create sample row that will be cloned
+ if(!this.templateRow) {
+ this.templateRow = rowDesc;
+ this.templateRow.setId("trow");
+ this.grid._parseRowAndAddToStrips(this.templateRow.id, this.templateRow);
+ this.templateRow.setRowIndex(-100);
+ this.templateRow.showEmpty();
+ this.templateRow.hide();
+ }
+
+ this.grid._parseRowAndAddToStrips("" + (this.grid._getParsedRowsCount()+1), rowDesc);
+ return rowDesc;
+ },
+ /**
+ * Parse values of cell's value and title
+ * Predefined patterns:
+ * - $(row) Index of current row
+ * - $(cid) Cell's DOM id
+ * - $(rid) Row's DOM id
+ * - $(N) Row Data index
+ * @param {Object} expr Value to parse. Can be defined over expression in next manner: "$(index_0) and $(index_4) will be over $(index_2) higher!". Where 1,5,3 - indexes in <code>data</code> array param.
+ * @param {Object} data Data to replace within expression.
+ */
+ parseExpression: function(expr, data, params) {
+ var pattern = /\$\(row\)/i;
+ var rez = expr.gsub(pattern, function(item) {
+ return params.row;
+ });
+ pattern = /\$\(cid\)/i;
+ rez = rez.gsub(pattern, function(item) {
+ return params.cid;
+ })
+ pattern = /\$\(rid\)/i;
+ rez = rez.gsub(pattern, function(item) {
+ return params.rid;
+ })
+
+ pattern = /\$\((\d*)\)/i;
+ rez = rez.gsub(pattern, function(item) {
+ if(!item || !item[1]) {
+ return "!ERROR!";
+ }
+ var index = parseFloat(item[1]);
+ return data.length > index ? data[index] : "!ERROR!";
+ });
+
+ return rez;
+ },
+ loadRow: function(index, id) {
+ var row = null;
+ if(this.dataViewHash) {
+ row = this.dataViewHash[index];
+ }
+ if(row===null && index!==null) {
+ row = this.dataView.findAll(function(item){return item && item.rowindex==index;});
+ row = row && row.length && row.length>0 ? row[0] : null;
+ }
+ if(row===null && id!==null){
+ var rowEl = document.getElementById(id);
+ if(rowEl!==null) {
+ index = rowEl.length ? rowEl[0].rowindex : rowEl.rowindex;
+ row = this.dataView.findAll(function(item){return item && item.rowindex==index;});
+ }
+ }
+ if(row) {
+ var rowData = this.grid.dataModel.getRow(index);
+ if(rowData && rowData.length && rowData.length > 0) {
+ row.loadRowData(row, index, rowData);
+ }
+ }
+ },
+ getRow: function() {
+ return this.rowsPool.length>0 ? this.rowsPool.pop() : this.createRow();
+ },
+ deleteRow: function(row) {
+ row.hide();
+ row.rowindex = -1;
+ this.rowsPool.push(row);
+ },
+ adjustDataPosition: function (pos) {
+ // small improvement
+ if(this.dataView.length > 0 && Math.abs(this.currentPos - pos)/this.defaultRowHeigh < this.dataDelta/2) {
+ return;
+ }
+
+ // 1. calculate direction and range to load next data
+ var forwardDir = this.currentPos <= pos;
+ this.currentPos = pos;
+
+ // first visible row index
+ var first = parseInt(pos / this.defaultRowHeight) - 1;
+ if(first < 0) first = 0;
+
+ // TODO: check direction and predict some next rows
+ var from = Math.max(first - this.dataDelta, 0);
+ var to = Math.min(first + this.dataVisible+this.dataDelta, this.grid.dataModel.getCount());
+ var range = $R(from, to);
+
+ if(from === to) {
+ ClientUILib.log(ClientUILogger.WARNING, "!!! GridBody: adjustDataPosition. Pos: " + pos + ", From:" + from + ", To:" + to);
+ return;
+ }
+
+ // 3. hide invisible rows
+ var dataViewHash = [];
+ var deleteRow = this.deleteRow.bind(this);
+ this.dataView.each(function(item) {
+ if(item && item.rowindex>=0) {
+ if(!range.include(item.rowindex)) {
+ deleteRow(item);
+ }
+ else {
+ dataViewHash[item.rowindex] = item;
+ }
+ }
+ });
+ // make some cleanup of deleted rows
+ this.dataView = this.dataView.findAll(function(item) {
+ return item && item.rowindex>=0;
+ });
+
+ // 4. show empty rows
+ var rowIndex = 0;
+ var rowsToLoad = [];
+ var rowsToLoadIdx = [];
+ var row, i;
+ for(i=range.start; i<=range.end; i++) {
+ if(!dataViewHash[i]) {
+ row = this.getRow();
+ row.setRowIndex(i);
+ row.showEmpty();
+ this.dataView.push(row);
+ dataViewHash[i] = row;
+ rowsToLoadIdx.push(i);
+ rowsToLoad.push(row.getCellsToUpdate());
+ rowIndex++
+ }
+ }
+ this.dataViewHash = dataViewHash;
+
+ if(rowIndex > 0) {
+ // stop timed adjusting
+ var task = this._getPendingTask();
+ clearTimeout(task.timer);
+ task.timer = null;
+
+ while(task.rowsToLoadIdx.length) {
+ var index = task.rowsToLoadIdx.pop();
+ var ids = task.rowsToLoad.pop();
+ if(dataViewHash[index]) {
+ rowsToLoadIdx.push(index);
+ rowsToLoad.push(ids);
+ }
+ }
+
+ task.rowsToLoadIdx = rowsToLoadIdx;
+ task.rowsToLoad = rowsToLoad;
+ this._setPendingTask(task);
+ }
+ },
+ _getPendingTask: function() {
+ if(!this.pendingTask) {
+ this.pendingTask = {
+ timer: null,
+ rowsToLoad: [],
+ rowsToLoadIdx: []
+ };
+ }
+ return this.pendingTask;
+ },
+ _setPendingTask: function(task) {
+ // and plan other agjusting over the time
+ task.timer = setTimeout(function() {
+
+ //ClientUILib.log(ClientUILogger.INFO, "Load data indexes: " + task.rowsToLoadIdx.inspect());
+ //ClientUILib.log(ClientUILogger.INFO, "ViewSize: " + this.dataView.length);
+ ClientUILib.log(ClientUILogger.INFO, "Load data indexes: " + task.rowsToLoad.inspect());
+
+ // 4. start data loading
+ this.grid.dataModel.loadRows({
+ indexes: task.rowsToLoadIdx,
+ ids: task.rowsToLoad});
+
+ task.timer = null;
+ task.rowsToLoad = [];
+ task.rowsToLoadIdx = [];
+ }.bind(this), this.grid.dataModel.getRequestDelay());
+
+ this.pendingTask = task;
+ },
+ invalidate: function(options) {
+ // load rows data
+ var byIndex = options.indexes!==null;
+ var count = options.indexes!==null ? options.indexes.length : (options.ids!==null?options.ids.lenth : 0);
+ var i,index,id,row;
+ for(i=0; i<count; i++) {
+ index = options.indexes!==null ? options.indexes[i] : null;
+ id = options.ids!==null ? options.ids[i] : null;
+ row = null;
+
+ if(index!==null) {
+ if(this.dataViewHash) {
+ row = this.dataViewHash[index];
+ }
+ if(!row) {
+ row = this.dataView.findAll(function(item){return item && item.rowindex==index;});
+ row = row && row.length && row.length>0 ? row[0] : null;
+ }
+ }
+ if(row===null && id!==null){
+ var rowEl = document.getElementById(id);
+ if(rowEl!==null) {
+ index = rowEl.length ? rowEl[0].rowindex : rowEl.rowindex;
+ row = this.dataView.findAll(function(item){return item && item.rowindex==index;});
+ }
+ }
+ if(row) {
+ row.showNormal();
+ }
+ }
+
+ // This trick to force IE rerender rows
+ if(ClientUILib.isIE && !ClientUILib.isIE7) {
+ this.setScrollPos(this.currentPos);
+ this.adjustScrollPosition(this.grid.getColumnScrollX());
+ }
+ }
+});
Added: trunk/sandbox/scrollable-grid/src/main/javascript/ClientUI/controls/grid/GridFooter.js
===================================================================
--- trunk/sandbox/scrollable-grid/src/main/javascript/ClientUI/controls/grid/GridFooter.js (rev 0)
+++ trunk/sandbox/scrollable-grid/src/main/javascript/ClientUI/controls/grid/GridFooter.js 2007-04-24 15:27:18 UTC (rev 518)
@@ -0,0 +1,260 @@
+/*
+ * TODO: Copyright (c) 2007 Denis Morozov <dmorozov(a)exadel.com>
+ *
+ * ...
+ */
+ClientUILib.declarePackage("ClientUI.controls.grid.GridFooter");
+
+ClientUILib.requireClass("ClientUI.common.box.Box");
+
+/*
+/* GridHeader.js - Grid control header pane
+ * TODO: add comments
+ */
+ClientUI.controls.grid.GridFooter = Class.create({
+ CLASSDEF: {
+ name: 'ClientUI.controls.grid.GridFooter',
+ parent: ClientUI.common.box.Box
+ }
+
+});
+
+Object.extend(ClientUI.controls.grid.GridFooter.prototype, {
+ initialize: function(template, grid) {
+ this.grid = grid;
+ ClientUI.controls.grid.GridFooter.parentClass.constructor().call(this);
+ this.element.id = this.grid.getElement().id + "_Footer";
+
+ this.createControl(template);
+ },
+ createControl: function(template) {
+ // validate template
+ var ch = $(template).firstChild;
+ while(ch) {
+ if(ch.tagName && ch.tagName.toLowerCase()=="table") {
+ this.template = $(ch);
+ break;
+ }
+ ch = ch.nextSibling;
+ }
+
+ template.parentNode.removeChild(template);
+ document.body.appendChild(template);
+
+ if(!this.template) {
+ var errMsg = "Invalid template specified. GridFooter requires template specified over table element.";
+ ClientUILib.log(ClientUILogger.ERROR, errMsg);
+ throw(errMsg);
+ }
+ if(!this.parseTemplate(this.template)) {
+ var errMsg = "Unable to parse template. GridFooter requires template specified over table element with one row.";
+ ClientUILib.log(ClientUILogger.ERROR, errMsg);
+ throw(errMsg);
+ }
+
+ this.contentBox = new ClientUI.common.box.Box(null, this.getElement());
+ this.contentBox.makeAbsolute();
+ this.frozenContentBox = new ClientUI.common.box.Box(null, this.getElement());
+ this.frozenContentBox.makeAbsolute();
+
+ // generate DOM objects tree
+ this.generateDOMTree();
+
+ // Remove template
+ document.body.removeChild(template);
+
+ // Set dimensions
+ this.setHeight(this.defaultHeight);
+ this.setWidth(this.defaultWidth);
+ this.controlCreated = true;
+ this.updateLayout();
+ },
+ getRow: function() {
+ if(!this.footerRow) {
+ var rowDesc = {
+ id: "footer",
+ frozen: this.headerFrozenRow,
+ normal: this.headerRow,
+ moveToY: function(y) {
+ this.frozen.moveToY(y);
+ this.normal.moveToY(y);
+ }
+ };
+
+ this.footerRow = rowDesc;
+ }
+
+ return this.footerRow;
+ },
+ parseTemplate: function(template) {
+ if(!template || !template.rows || template.rows.length===0) {
+ return false;
+ }
+
+ var columns = [];
+
+ // Get columns information
+ var i = 0;
+ if(this.grid.options.showIndexColumn) {
+ columns[i++] = {
+ innerHTML: " ",
+ styleClass: "",
+ id: "",
+ align: "",
+ valign: "",
+ title: ""
+ };
+ }
+
+ var cells = $A(template.rows[0].cells);
+ cells.each(function(cell) {
+ columns[i++] = {
+ innerHTML: cell.innerHTML,
+ styleClass: cell.className,
+ id: cell.id,
+ align: cell.align,
+ valign: cell.vAlign,
+ title: cell.title
+ };
+ Element.addClassName(cell, "ClientUI_Grid_FCBody");
+ });
+
+ this._columns = columns;
+ this.defaultHeight = Element.getHeight(template.rows[0].cells[0]);
+ if(ClientUILib.isGecko) {
+ this.defaultHeight -= this.getBorderWidth("tb") + this.getPadding("tb");
+ }
+
+ return true;
+ },
+ generateDOMTree: function() {
+ var headerRow = new ClientUI.common.box.InlineBox(null, this.contentBox.getElement());
+ headerRow.getElement().addClassName("ClientUI_Grid_FR");
+ headerRow.getElement().id = this.getElement().id + "FR";
+ headerRow.setHeight(this.defaultHeight)
+
+ var headerFrozenRow = new ClientUI.common.box.InlineBox(headerRow.getElement().cloneNode(true));
+ headerFrozenRow.setParent(this.frozenContentBox.getElement());
+ headerFrozenRow.getElement().setAttribute("id", this.getElement().id + "FRFroz");
+
+ var columnZIndex = this.grid.getHeader().getColumns().length*2 + 10;
+ var lastFrozenZIndex = columnZIndex;
+ var frozenContentBox = this.frozenContentBox;
+ var rowHeight = headerRow.getViewportHeight();
+ var defaultWidth = 0;
+ var defaultWidthFrozen = 0;
+ var columns = this._columns;
+ var i = 0;
+ this.grid.getHeader().getColumns().each(function(headerColumnDesc) {
+ var columnDesc = columns[i++];
+
+ // create footer cell
+ var parent = headerColumnDesc.frozen ? headerFrozenRow.getElement() : headerRow.getElement();
+ var col = new ClientUI.common.box.InlineBox(null, parent);
+ col.getElement().addClassName("ClientUI_Grid_FC");
+ col.setStyle({zIndex: columnZIndex});
+ if(headerColumnDesc.frozen) {
+ lastFrozenZIndex = columnZIndex;
+ }
+ columnZIndex -= 2;
+
+ if(!Validators.isEmpty(columnDesc.styleClass)) {
+ col.getElement().addClassName(columnDesc.styleClass);
+ }
+ if(!Validators.isEmpty(columnDesc.id)) {
+ col.getElement().id = columnDesc.id;
+ }
+ if(!Validators.isEmpty(columnDesc.title)) {
+ col.getElement().title = columnDesc.title;
+ }
+ if(!Validators.isEmpty(columnDesc.valign)) {
+ col.getElement().setStyle({verticalAlign: columnDesc.valign});
+ }
+
+ // get cell width from header
+ var width = headerColumnDesc.object.getWidth();
+ col.setWidth(width);
+ col.setHeight(rowHeight);
+ col.makeAbsolute();
+ columnDesc.object = col;
+ if(!headerColumnDesc.frozen) {
+ col.moveToX(defaultWidth);
+ defaultWidth += width;
+ }
+ else {
+ col.moveToX(defaultWidthFrozen);
+ defaultWidthFrozen += width;
+ }
+
+ // header cell body
+ var colBody = new ClientUI.common.box.InlineBox(null, col.getElement());
+ colBody.getElement().addClassName("ClientUI_Grid_FCBody");
+ // glue cell content
+ var sb = new StringBuilder('<table width="100%" ');
+ if(!Validators.isEmpty(columnDesc.align)) {
+ sb.append('align="').append(columnDesc.align).append('" ');
+ }
+ sb.append('cellspacing="0" cellpadding="0" border="0"><tbody><tr><td width="100%"><span style="width:100%">');
+ if(!Validators.isEmpty(columnDesc.innerHTML)) {
+ sb.append(columnDesc.innerHTML);
+ }
+ sb.append('</span></td></tr></tbody></table>');
+ colBody.getElement().update(sb.toString());
+ colBody.moveTo(0, 0);
+ var bodyWidth = width;
+ var bodyHeight = rowHeight;
+ if(ClientUILib.isGecko) {
+ bodyWidth -= colBody.getBorderWidth("lr") + colBody.getPadding("lr");
+ bodyHeight -= colBody.getBorderWidth("tb") + colBody.getPadding("tb");
+ }
+ colBody.setWidth(bodyWidth);
+ colBody.setHeight(bodyHeight);
+ });
+
+ this.defaultWidth = defaultWidth;
+ if(ClientUILib.isGecko) {
+ this.defaultWidth -= this.getBorderWidth("lr") + this.getPadding("lr");
+ }
+
+ this.headerRow = headerRow;
+ this.headerFrozenRow = headerFrozenRow;
+ if(ClientUILib.isIE) {
+ this.substrate = new ClientUI.common.box.Substrate(null, this.getElement());
+ this.substrate.getElement().name = this.getElement().id + "FRFrm";
+ this.substrate.setStyle({zIndex: lastFrozenZIndex-1});
+ this.substrate.setHeight(rowHeight);
+ }
+ },
+ getColumns: function() {
+ return this._columns;
+ },
+ updateLayout: function() {
+ if(!this.controlCreated || !this.grid.controlCreated) {
+ return;
+ }
+ ClientUI.controls.grid.GridFooter.parentClass.method("updateLayout").call(this);
+
+ var height = this.getViewportHeight();
+ var totalWidth = this.grid.getColumnsTotalWidth();
+ var frozenContentWidth = this.grid.getColumnsFrozenWidth();
+
+ this.contentBox.setWidth(Math.max(this.getWidth(), totalWidth));
+ this.contentBox.setHeight(height);
+ this.contentBox.moveTo(frozenContentWidth, 0);
+ this.frozenContentBox.setWidth(frozenContentWidth);
+ this.frozenContentBox.setHeight(height);
+ this.frozenContentBox.moveTo(0, 0);
+ var row = this.getRow();
+ row.frozen.setWidth(frozenContentWidth);
+ row.normal.setWidth(Math.max(this.getWidth(), totalWidth));
+ var frozenContentWidth = this.grid.getBody().frozenContentBox.getWidth();
+ var width = frozenContentWidth+this.grid.getBody().contentBox.getWidth();
+ this.setWidth(width);
+ if(ClientUILib.isIE)
+ this.substrate.setWidth(frozenContentWidth);
+ this.adjustScrollPosition(this.grid.getColumnScrollX());
+ },
+ adjustScrollPosition: function(pos) {
+ this.contentBox.moveToX(this.grid.getColumnsFrozenWidth()-pos);
+ }
+})
Added: trunk/sandbox/scrollable-grid/src/main/javascript/ClientUI/controls/grid/GridHeader.js
===================================================================
--- trunk/sandbox/scrollable-grid/src/main/javascript/ClientUI/controls/grid/GridHeader.js (rev 0)
+++ trunk/sandbox/scrollable-grid/src/main/javascript/ClientUI/controls/grid/GridHeader.js 2007-04-24 15:27:18 UTC (rev 518)
@@ -0,0 +1,423 @@
+/*
+ * TODO: Copyright (c) 2007 Denis Morozov <dmorozov(a)exadel.com>
+ *
+ * ...
+ */
+ClientUILib.declarePackage("ClientUI.controls.grid.GridHeader");
+
+ClientUILib.requireClass("ClientUI.common.box.Box");
+ClientUILib.requireClass("ClientUI.common.box.InlineBox");
+
+/*
+ * GridHeader.js - Grid control header pane
+ * TODO: add comments
+ */
+ClientUI.controls.grid.GridHeader = Class.create({
+ CLASSDEF: {
+ name: 'ClientUI.controls.grid.GridHeader',
+ parent: ClientUI.common.box.Box,
+ sepStyleClass: "ClientUI_Grid_HSep"
+ }
+
+});
+
+Object.extend(ClientUI.controls.grid.GridHeader.prototype, {
+ // internal variables
+ _columns: [],
+
+ // constructor
+ initialize: function(template, grid) {
+ this.grid = grid;
+ ClientUI.controls.grid.GridHeader.parentClass.constructor().call(this);
+ this.element.id = this.grid.getElement().id + "_Header";
+
+ // register event handlers
+ this.eventSepDblClick = this.OnSepDblClick.bindAsEventListener(this);
+ this.eventSepMouseDown = this.OnSepMouseDown.bindAsEventListener(this);
+ this.eventSepMouseUp = this.OnSepMouseUp.bindAsEventListener(this);
+ this.eventSepMouseMove = this.OnSepMouseMove.bindAsEventListener(this);
+ this.eventCellMouseDown = this.OnCellMouseDown.bindAsEventListener(this);
+ Event.observe(document, 'mousemove', this.eventSepMouseMove, true);
+ Event.observe(document, 'mouseup', this.eventSepMouseUp, true);
+
+ this.createControl(template);
+ },
+
+ // create grid header control
+ createControl: function(template) {
+
+ // validate template
+ var ch = $(template).firstChild;
+ while(ch) {
+ if(ch.tagName && ch.tagName.toLowerCase()=="table") {
+ this.template = $(ch);
+ break;
+ }
+ ch = ch.nextSibling;
+ }
+
+ template.parentNode.removeChild(template);
+ document.body.appendChild(template);
+
+ var errMsg = "";
+ if(!this.template) {
+ errMsg = "Invalid template specified. GridHeader requires template specified over table element.";
+ ClientUILib.log(ClientUILogger.ERROR, errMsg);
+ throw(errMsg);
+ }
+ if(!this.parseTemplate(this.template)) {
+ errMsg = "Unable to parse template. GridHeader requires template specified over table element with one row.";
+ ClientUILib.log(ClientUILogger.ERROR, errMsg);
+ throw(errMsg);
+ }
+
+ this.contentBox = new ClientUI.common.box.Box(null, this.getElement());
+ this.contentBox.makeAbsolute();
+ this.frozenContentBox = new ClientUI.common.box.Box(null, this.getElement());
+ this.frozenContentBox.makeAbsolute();
+
+ // generate DOM objects tree
+ this.generateDOMTree();
+
+ // Remove template
+ document.body.removeChild(template);
+
+ // Set dimensions
+ this.setHeight(this.defaultHeight);
+ this.setWidth(this.defaultWidth);
+ this.controlCreated = true;
+ this.updateLayout();
+ },
+ parseTemplate: function(template) {
+ if(!template || !template.rows || template.rows.length===0) {
+ return false;
+ }
+
+ var columns = [];
+ var defaultWidth = 0;
+
+ var i = 0;
+ if(this.grid.options.showIndexColumn) {
+ columns[i++] = {
+ width: this.grid.options.indexColumnWidth,
+ innerHTML: " ",
+ styleClass: "",
+ id: "",
+ align: "",
+ valign: "",
+ title: "",
+ minWidth: this.grid.options.indexColumnWidth,
+ frozen: true,
+ fixedWidth: true,
+ sortable: false,
+ sorted: "asc"
+ };
+ }
+
+ // Get columns information
+ var cells = $A(template.rows[0].cells);
+ cells.each(function(cell) {
+ columns[i++] = {
+ width: Element.getWidth(cell),
+ innerHTML: cell.innerHTML,
+ styleClass: cell.className,
+ id: cell.id,
+ align: cell.align,
+ valign: cell.vAlign,
+ title: cell.title,
+ minWidth: 10,
+ frozen: Validators.getBoolean(cell.getAttribute("frozen"), false),
+ fixedWidth: Validators.getBoolean(cell.getAttribute("fixedWidth"), false),
+ sortable: Validators.getBoolean(cell.getAttribute("sortable"), true),
+ sorted: Validators.getBoolean(cell.getAttribute("sorted"), "desc")
+ };
+
+ defaultWidth += Element.getWidth(cell);
+ Element.addClassName(cell, "ClientUI_Grid_HCBody");
+ });
+
+ this._columns = columns;
+ this.defaultHeight = Element.getHeight(template.rows[0].cells[0]);
+ this.defaultWidth = defaultWidth;
+ if(ClientUILib.isGecko) {
+ this.defaultWidth -= this.getBorderWidth("lr") + this.getPadding("lr");
+ this.defaultHeight -= this.getBorderWidth("tb") + this.getPadding("tb");
+ }
+
+ return true;
+ },
+ generateDOMTree: function() {
+ var headerRow = new ClientUI.common.box.InlineBox(null, this.contentBox.getElement());
+ headerRow.getElement().addClassName("ClientUI_Grid_HR");
+ headerRow.getElement().id = this.getElement().id + "HR";
+ headerRow.setWidth(this.defaultWidth + 10000);
+ headerRow.setHeight(this.defaultHeight);
+
+ var headerFrozenRow = new ClientUI.common.box.InlineBox(headerRow.getElement().cloneNode(true));
+ headerFrozenRow.setParent(this.frozenContentBox.getElement());
+ headerFrozenRow.getElement().setAttribute("id", this.getElement().id + "FRFroz");
+
+ var eventSepDblClick = this.eventSepDblClick.bind(this);
+ var eventSepMouseDown = this.eventSepMouseDown.bind(this);
+ var eventCellMouseDown = this.eventCellMouseDown.bind(this);
+
+ // create all columns
+ var columnZIndex = this._columns.length*3 + 10;
+ var lastFrozenZIndex = columnZIndex;
+ var frozenContentBox = this.frozenContentBox;
+ var defaultWidth = 0;
+ var defaultWidthFrozen = 0;
+ var index = 0;
+ var height = headerRow.getViewportHeight();
+ this._columns.each(function(columnDesc) {
+ var width = !Validators.isEmpty(columnDesc.width) ? columnDesc.width : 100;
+
+ var parent = columnDesc.frozen ? headerFrozenRow.getElement() : headerRow.getElement();
+ var col = new ClientUI.common.box.InlineBox(null, parent);
+ col.collindex = index;
+ col.getElement().addClassName("ClientUI_Grid_HC");
+ col.getElement().columnIndex = index;
+ col.getElement().setStyle({zIndex: columnZIndex-1});
+ if(!Validators.isEmpty(columnDesc.id)) {
+ col.getElement().id = columnDesc.id;
+ }
+ if(!Validators.isEmpty(columnDesc.title)) {
+ col.getElement().title = columnDesc.title;
+ }
+ if(!Validators.isEmpty(columnDesc.valign)) {
+ col.getElement().setStyle({verticalAlign: columnDesc.valign});
+ }
+
+ col.setWidth(width);
+ col.setHeight(height);
+ col.makeAbsolute();
+ columnDesc.object = col;
+
+ if(columnDesc.sortable) {
+ Event.observe(col.getElement(), 'click', eventCellMouseDown);
+ }
+
+ if(!columnDesc.frozen) {
+ col.moveToX(defaultWidth);
+ }
+ else {
+ col.moveToX(defaultWidthFrozen);
+ }
+
+ // header cell body
+ var colBody = new ClientUI.common.box.InlineBox(null, col.getElement());
+ columnDesc.body = colBody;
+ if(!Validators.isEmpty(columnDesc.styleClass)) {
+ colBody.getElement().addClassName(columnDesc.styleClass);
+ }
+ colBody.getElement().addClassName("ClientUI_Grid_HCBody");
+
+ // glue cell content
+ var sb = new StringBuilder('<table width="100%" ');
+ if(!Validators.isEmpty(columnDesc.align)) {
+ sb.append('align="').append(columnDesc.align).append('" ');
+ }
+ sb.append('cellspacing="0" cellpadding="0" border="0"><tbody><tr><td width="100%"><span style="width:100%">');
+ if(!Validators.isEmpty(columnDesc.innerHTML)) {
+ sb.append(columnDesc.innerHTML);
+ }
+ sb.append('</span></td><td><span class="sort-desc"></span><span class="sort-asc"></span></td></tr></tbody></table>');
+ colBody.getElement().update(sb.toString());
+ colBody.moveTo(0, 0);
+ var bodyWidth = width;
+ var bodyHeight = height;
+ if(ClientUILib.isGecko) {
+ bodyWidth -= colBody.getBorderWidth("lr") + colBody.getPadding("lr");
+ bodyHeight -= colBody.getBorderWidth("tb") + colBody.getPadding("tb");
+ }
+ colBody.setWidth(bodyWidth);
+ colBody.setHeight(bodyHeight);
+ columnDesc.sortAsc = document.getElementsByClassName("sort-asc", colBody.getElement())[0];
+ columnDesc.sortDesc = document.getElementsByClassName("sort-desc", colBody.getElement())[0];
+
+ // create separator between header's cells
+ var sep = new ClientUI.common.box.InlineBox(null, parent);
+ sep.getElement().addClassName("ClientUI_Grid_HSep");
+ sep.makeAbsolute();
+ if(!columnDesc.frozen) {
+ sep.moveToX(defaultWidth + width - sep.getWidth()/2 - 1);
+ }
+ else {
+ sep.moveToX(defaultWidthFrozen + width - sep.getWidth()/2 - 1);
+ lastFrozenZIndex = columnZIndex;
+ }
+ sep.getElement().columnIndex = index;
+ sep.getElement().setStyle({zIndex: columnZIndex});
+ columnDesc.sep = sep;
+
+ if(!columnDesc.fixedWidth) {
+ Event.observe(sep.getElement(), 'dblclick', eventSepDblClick);
+ Event.observe(sep.getElement(), 'mousedown', eventSepMouseDown);
+ }
+ else {
+ sep.getElement().setStyle({cursor: 'auto'});
+ }
+
+ columnZIndex -= 3;
+ if(!columnDesc.frozen) {
+ defaultWidth += width;
+ }
+ else {
+ defaultWidthFrozen += width;
+ }
+ index++;
+ });
+
+ this.headerRow = headerRow;
+ this.headerFrozenRow = headerFrozenRow;
+ this.frozenSubstrate = new ClientUI.common.box.Substrate(null, headerFrozenRow.getElement());
+ this.frozenSubstrate.getElement().name = this.getElement().id + "HRFrm";
+ this.frozenSubstrate.setStyle({zIndex: lastFrozenZIndex-2});
+ this.frozenSubstrate.setHeight(headerRow.getViewportHeight());
+ },
+ getRow: function() {
+ if(!this.footerRow) {
+ var rowDesc = {
+ id: "header",
+ frozen: this.headerFrozenRow,
+ normal: this.headerRow,
+ moveToY: function(y) {
+ this.frozen.moveToY(y);
+ this.normal.moveToY(y);
+ }
+ };
+
+ this.footerRow = rowDesc;
+ }
+
+ return this.footerRow;
+ },
+ updateLayout: function() {
+ if(!this.controlCreated || !this.grid.controlCreated) {
+ return;
+ }
+ ClientUI.controls.grid.GridHeader.parentClass.method("updateLayout").call(this);
+
+ var height = this.getViewportHeight();
+ var totalWidth = this.grid.getColumnsTotalWidth();
+ var frozenContentWidth = this.grid.getColumnsFrozenWidth();
+
+ this.contentBox.setWidth(Math.max(this.getWidth(), totalWidth));
+ this.contentBox.setHeight(height);
+ this.contentBox.moveTo(frozenContentWidth, 0);
+ this.frozenContentBox.setWidth(frozenContentWidth);
+ this.frozenContentBox.setHeight(height);
+ this.frozenContentBox.moveTo(0, 0);
+ this.frozenSubstrate.setWidth(frozenContentWidth);
+ var row = this.getRow();
+ row.frozen.setWidth(frozenContentWidth);
+ row.normal.setWidth(Math.max(this.getWidth(), totalWidth));
+ },
+ getColumns: function() {
+ return this._columns;
+ },
+ // lets implement column resizer
+ OnSepMouseDown: function(event) {
+ this.dragColumnInfo = {
+ srcElement: Event.element(event),
+ dragStarted: false,
+ mouseDown: true,
+ startX: Event.pointerX(event),
+ originalX: 0
+ };
+ this.dragColumnInfo.object = this.getColumns()[this.dragColumnInfo.srcElement.columnIndex].object;
+ this.dragColumnInfo.sep = this.getColumns()[this.dragColumnInfo.srcElement.columnIndex].sep;
+ this.dragColumnInfo.minWidth = this.getColumns()[this.dragColumnInfo.srcElement.columnIndex].minWidth;
+
+ Event.stop(event);
+ },
+ OnSepMouseUp: function(event) {
+ if(this.dragColumnInfo && this.dragColumnInfo.dragStarted) {
+ this.dragColumnInfo.dragStarted = false;
+ this.dragColumnInfo.mouseDown = false;
+ var delta = Event.pointerX(event) - this.dragColumnInfo.startX;
+ var newWidth = this.dragColumnInfo.object.getWidth() + delta;
+ setTimeout(function() {
+ this.grid.adjustColumnWidth(this.dragColumnInfo.srcElement.columnIndex, newWidth);
+ }.bind(this), 10);
+ }
+ this._hideSplitter();
+ },
+ OnSepMouseMove: function(event) {
+ if(this.dragColumnInfo && this.dragColumnInfo.mouseDown) {
+ if(!this.dragColumnInfo.dragStarted) {
+ this.dragColumnInfo.dragStarted = true;
+ this._showSplitter(this.dragColumnInfo.srcElement.columnIndex);
+ }
+ else {
+ var delta = Event.pointerX(event) - this.dragColumnInfo.startX;
+ var minColumnWidth = this.dragColumnInfo.object.getWidth() - this.dragColumnInfo.minWidth;
+ if(delta >= -minColumnWidth) {
+ var x = this.dragColumnInfo.originalX + delta;
+ this.columnSplitter.moveToX(x - 6);
+ }
+ }
+ Event.stop(event);
+ }
+ },
+ OnSepDblClick: function(event) {
+ ClientUILib.log(ClientUILogger.INFO, "OnSepDblClick");
+ },
+ _showSplitter: function(index) {
+ if(!this.columnSplitter) {
+ this._createSplitter();
+ }
+
+ var pos = this.dragColumnInfo.sep.getX();
+ if(!this.getColumns()[index].frozen) {
+ pos += this.grid.getColumnsFrozenWidth() - this.grid.getColumnScrollX(index);
+ }
+ this.dragColumnInfo.originalX = pos;
+ this.columnSplitter.show();
+ this.columnSplitter.setHeight(this.defaultHeight + this.grid.getBody().contentBox.getHeight());
+ this.columnSplitter.moveTo(pos, 0);
+ },
+ _hideSplitter: function() {
+ if(this.columnSplitter) {
+ this.columnSplitter.hide();
+ }
+ },
+ _createSplitter: function() {
+ this.columnSplitter = new ClientUI.common.box.Box(null, this.grid.getElement());
+ this.columnSplitter.makeAbsolute();
+ this.columnSplitter.getElement().addClassName("ClientUI_Grid_HSplit");
+ this.columnSplitter.setWidth(10);
+ this.columnSplitter.getElement().setStyle({backgroundColor: ''});
+ this.columnSplitter.getElement().setStyle({zIndex: '100'});
+ this.columnSplitter.hide();
+ },
+ adjustScrollPosition: function(pos) {
+ this.contentBox.moveToX(this.grid.getColumnsFrozenWidth()-pos);
+ },
+ OnCellMouseDown: function(event) {
+ var el = Event.element(event);
+ while(el && !Element.hasClassName(el, "ClientUI_Grid_HC")) {
+ el = el.parentNode;
+ }
+
+ if(el && el.columnIndex>=0) {
+ var order = this.getColumns()[el.columnIndex].sorted;
+ order = (order == "asc") ? "desc" : "asc";
+ this.getColumns()[el.columnIndex].sorted = order;
+
+ for(var i = 0, len = this.getColumns().length; i < len; i++) {
+ var h = this.getColumns()[i];
+ if(i != el.columnIndex) {
+ Element.setStyle(h.sortDesc, {display: 'none'});
+ Element.setStyle(h.sortAsc, {display: 'none'});
+ } else{
+ Element.setStyle(h.sortDesc, {display: (order == 'desc' ? 'block' : 'none')});
+ Element.setStyle(h.sortAsc, {display: (order == 'asc' ? 'block' : 'none')});
+ }
+ }
+
+ this.grid.eventOnSort.fire(el.columnIndex, order);
+ Event.stop(event);
+ }
+ }
+});
Added: trunk/sandbox/scrollable-grid/src/main/javascript/ClientUI/layouts/GridLayoutManager.js
===================================================================
--- trunk/sandbox/scrollable-grid/src/main/javascript/ClientUI/layouts/GridLayoutManager.js (rev 0)
+++ trunk/sandbox/scrollable-grid/src/main/javascript/ClientUI/layouts/GridLayoutManager.js 2007-04-24 15:27:18 UTC (rev 518)
@@ -0,0 +1,75 @@
+/*
+ * TODO: Copyright (c) 2007 Denis Morozov <dmorozov(a)exadel.com>
+ *
+ * ...
+ */
+ClientUILib.declarePackage("ClientUI.layouts.GridLayoutManager");
+
+ClientUILib.requireClass("ClientUI.common.box.Box");
+ClientUILib.requireClass("ClientUI.layouts.VLayoutManager");
+
+var GridLayout_Enum = {
+ HEADER: 1,
+ BODY: 2,
+ FOOTER: 3
+};
+
+/*
+ * LayoutManager.js - Base class for all layout managers
+ * by Denis Morozov <dmorozov(a)exadel.com> distributed under the BSD license.
+ *
+ * TODO: description of control
+ */
+ClientUI.layouts.GridLayoutManager = Class.create({
+ CLASSDEF: {
+ name: 'ClientUI.layouts.GridLayoutManager',
+ parent: ClientUI.layouts.VLayoutManager
+ }
+
+});
+
+Object.extend(ClientUI.layouts.GridLayoutManager.prototype, {
+ initialize: function(element, parentElement, config) {
+ ClientUI.layouts.GridLayoutManager.parentClass.constructor().call(this, element, parentElement);
+ },
+ updateLayout: function() {
+ ClientUI.layouts.LayoutManager.method("updateLayout").call(this);
+
+ var parentBox = this.getContainer();
+ var height = parentBox.getViewportHeight();
+ var width = parentBox.getViewportWidth();
+
+ // NOTE: not implemented in this class
+ if(this.panels) {
+ var headerHeight = 0;
+ var footerHeight = 0;
+ var bodyBottom = 0;
+
+ // first get size of header
+ if(this.panels[GridLayout_Enum.HEADER]) {
+ headerHeight = this.panels[GridLayout_Enum.HEADER].getHeight();
+ this.panels[GridLayout_Enum.HEADER].moveTo(0, 0);
+ this.panels[GridLayout_Enum.HEADER].setWidth(width);
+ this.panels[GridLayout_Enum.HEADER].updateLayout();
+ }
+ // than calculate size of body
+ if(this.panels[GridLayout_Enum.BODY]) {
+ var body = this.panels[GridLayout_Enum.BODY];
+ body.setWidth(width);
+ var bodyHeight = height - headerHeight;
+ body.setHeight(bodyHeight);
+ body.moveTo(0, headerHeight);
+ body.updateLayout();
+ bodyBottom = body.getY() + body.contentBox.getY() + body.scrollBox.getViewportHeight();
+ }
+
+ if(this.panels[GridLayout_Enum.FOOTER]) {
+ footerHeight = this.panels[GridLayout_Enum.FOOTER].getHeight();
+ this.panels[GridLayout_Enum.FOOTER].moveTo(0, bodyBottom - footerHeight);
+ this.panels[GridLayout_Enum.FOOTER].setWidth(width);
+ this.panels[GridLayout_Enum.FOOTER].updateLayout();
+ }
+
+ }
+ }
+});
\ No newline at end of file
Added: trunk/sandbox/scrollable-grid/src/main/javascript/ClientUI/layouts/LayoutManager.js
===================================================================
--- trunk/sandbox/scrollable-grid/src/main/javascript/ClientUI/layouts/LayoutManager.js (rev 0)
+++ trunk/sandbox/scrollable-grid/src/main/javascript/ClientUI/layouts/LayoutManager.js 2007-04-24 15:27:18 UTC (rev 518)
@@ -0,0 +1,71 @@
+/*
+ * TODO: Copyright (c) 2007 Denis Morozov <dmorozov(a)exadel.com>
+ *
+ * ...
+ */
+ClientUILib.declarePackage("ClientUI.layouts.LayoutManager");
+
+/*
+/* LayoutManager.js - Base class for all layout managers
+ * by Denis Morozov <dmorozov(a)exadel.com> distributed under the BSD license.
+ *
+ * TODO: description of control
+ */
+ClientUI.layouts.LayoutManager = Class.create({
+ CLASSDEF: {
+ name: 'ClientUI.layouts.LayoutManager',
+ parent: ClientUI.common.box.Box
+ }
+
+});
+
+Object.extend(ClientUI.layouts.LayoutManager.prototype, {
+ initialize: function(element, parentElement) {
+ ClientUI.layouts.LayoutManager.parentClass.constructor().call(this, element, parentElement);
+
+ // store container element to look after
+ this.container = parentElement;
+ if(this.container)
+ this.container = new ClientUI.common.box.Box($(this.container));
+
+ // declare event listeners
+ this.eventContainerResize = this.containerResize.bindAsEventListener(this);
+
+ this.registerEvents();
+ },
+ registerEvents: function() {
+ if(this.container)
+ Event.observe(window, "resize", this.eventContainerResize);
+ },
+ destroy: function() {
+ if(this.container)
+ Event.stopObserving(window, "resize", this.eventContainerResize);
+ },
+ containerResize: function(event) {
+ //Event.stop(event);
+ // TODO:
+ this.updateLayout();
+ },
+ updateLayout: function() {
+ if(this.container) {
+ this.setWidth(this.container.getWidth());
+ this.setHeight(this.container.getHeight());
+ }
+ ClientUI.layouts.LayoutManager.parentClass.method("updateLayout").call(this);
+ },
+ getContainer: function() {
+ return this.container;
+ }
+})
+
+/*
+ Vertically and horizontally centering a div that follow scrolling:
+
+ if(navigator.appName.search(/opera/gi) != -1) { // Using Opera
+ _element.style.top = Math.round(((document.body.clientHeight-document.documentElement.offsetHeight)/2)-(_element.style.height/2)+document.documentElement.scrollTop)+'px';
+ }
+ else { // Using IE / Firefox / Other
+ _element.style.left = Math.round((document.documentElement.clientWidth/2)-(_element.style.width/2))+"px";
+ _element.style.top = Math.round((document.documentElement.clientHeight/2)-(_element.style.height/2)+document.documentElement.scrollTop)+"px";
+ }
+ */
\ No newline at end of file
Added: trunk/sandbox/scrollable-grid/src/main/javascript/ClientUI/layouts/VLayoutManager.js
===================================================================
--- trunk/sandbox/scrollable-grid/src/main/javascript/ClientUI/layouts/VLayoutManager.js (rev 0)
+++ trunk/sandbox/scrollable-grid/src/main/javascript/ClientUI/layouts/VLayoutManager.js 2007-04-24 15:27:18 UTC (rev 518)
@@ -0,0 +1,98 @@
+/*
+ * TODO: Copyright (c) 2007 Denis Morozov <dmorozov(a)exadel.com>
+ *
+ * ...
+ */
+ClientUILib.declarePackage("ClientUI.layouts.VLayoutManager");
+
+ClientUILib.requireClass("ClientUI.common.box.Box");
+ClientUILib.requireClass("ClientUI.layouts.LayoutManager");
+
+var GridLayout_Enum = {
+ HEADER: 1,
+ BODY: 2,
+ FOOTER: 3
+};
+
+/*
+ * LayoutManager.js - Base class for all layout managers
+ * by Denis Morozov <dmorozov(a)exadel.com> distributed under the BSD license.
+ *
+ * TODO: description of control
+ */
+ClientUI.layouts.VLayoutManager = Class.create({
+ CLASSDEF: {
+ name: 'ClientUI.layouts.VLayoutManager',
+ parent: ClientUI.layouts.LayoutManager
+ }
+
+});
+
+Object.extend(ClientUI.layouts.VLayoutManager.prototype, {
+ initialize: function(element, parentElement, config) {
+ ClientUI.layouts.VLayoutManager.parentClass.constructor().call(this, element, parentElement);
+ if(!element || !element.id) {
+ this.element.id = "ClientUI_VLayoutManager" + ClientUI_layouts_VLayoutManager_idGenerator++;
+ }
+
+ this.registerEvents();
+ },
+ registerEvents: function() {
+ ClientUI.layouts.VLayoutManager.parentClass.method("registerEvents").call(this);
+ },
+ destroy: function() {
+ ClientUI.layouts.VLayoutManager.parentClass.method("destroy").call(this);
+ },
+ containerResize: function(event) {
+ ClientUI.layouts.VLayoutManager.parentClass.method("containerResize").call(this, event);
+ this.updateLayout();
+ },
+ addPane: function(align, pane) {
+ if(!this.panels) { this.panels = []; }
+
+ this.panels[align] = pane;
+ this.panels[align].makeAbsolute();
+ this.panels[align].setParent(this);
+ },
+ getPane: function(align) {
+ return this.panels[align];
+ },
+ updateLayout: function() {
+ ClientUI.layouts.VLayoutManager.parentClass.method("updateLayout").call(this);
+
+ var parentBox = this.getContainer();
+ var height = parentBox.getViewportHeight();
+ var width = parentBox.getViewportWidth();
+
+ // NOTE: not implemented in this class
+ if(this.panels) {
+ var headerHeight = 0;
+ var footerHeight = 0;
+
+ // first get size of header
+ if(this.panels[GridLayout_Enum.HEADER]) {
+ headerHeight = this.panels[GridLayout_Enum.HEADER].getHeight();
+ this.panels[GridLayout_Enum.HEADER].moveTo(0, 0);
+ this.panels[GridLayout_Enum.HEADER].setWidth(width);
+ this.panels[GridLayout_Enum.HEADER].updateLayout();
+ }
+ if(this.panels[GridLayout_Enum.FOOTER]) {
+ footerHeight = this.panels[GridLayout_Enum.FOOTER].getHeight();
+ this.panels[GridLayout_Enum.FOOTER].moveTo(0, height - footerHeight);
+ this.panels[GridLayout_Enum.FOOTER].setWidth(width);
+ this.panels[GridLayout_Enum.FOOTER].updateLayout();
+ }
+ // than calculate size of body
+ if(this.panels[GridLayout_Enum.BODY]) {
+ var body = this.panels[GridLayout_Enum.BODY];
+ body.setWidth(width);
+ var bodyHeight = height - (headerHeight + footerHeight);
+ body.setHeight(bodyHeight);
+ body.moveTo(0, headerHeight);
+ body.updateLayout();
+ }
+ }
+ }
+});
+
+var ClientUI_layouts_VLayoutManager_idGenerator = 0;
\ No newline at end of file
Added: trunk/sandbox/scrollable-grid/src/main/javascript/ClientUILib.js
===================================================================
--- trunk/sandbox/scrollable-grid/src/main/javascript/ClientUILib.js (rev 0)
+++ trunk/sandbox/scrollable-grid/src/main/javascript/ClientUILib.js 2007-04-24 15:27:18 UTC (rev 518)
@@ -0,0 +1,209 @@
+// ClientUILib base.js v1.0.0, Fri Jan 19 19:16:36 CET 2007
+
+// TODO: Copyright (c) 2007, Denis Morozov (dmorozov(a)exadel.com)
+// ...
+
+var ClientUILib = {
+ Version: '1.0.0',
+ Name: 'ClientUILib',
+ LibraryPath: './',
+ packages: [],
+ load: function(showLog) {
+ // Check for Prototype JavaScript framework
+ if((typeof Prototype=='undefined') ||
+ (typeof Element == 'undefined') ||
+ (typeof Element.Methods=='undefined') ||
+ parseFloat(Prototype.Version.split(".")[0] + "." +
+ Prototype.Version.split(".")[1]) < 1.5)
+ throw("ClientUILib requires the Prototype JavaScript framework >= 1.5.0");
+
+ // Check for Extend JavaScript library
+ if((typeof Extend=='undefined') ||
+ Extend.VERSION < 1.1)
+ throw("ClientUILib requires the Extend JavaScript library >= 1.1");
+
+ $A(document.getElementsByTagName("script")).findAll( function(s) {
+ return (s.src && s.src.match(/ClientUILib\.js(\?.*)?$/))
+ }).each( function(s) {
+ LibraryPath = s.src.replace(/ClientUILib\.js(\?.*)?$/,'');
+ });
+
+ if(showLog) {
+ ClientUILogger.create("ClientUILogger");
+ this.startTime = (new Date()).getTime();
+ }
+
+ this.initBrowser();
+ },
+ include: function(libraryPackageName) {
+ if(!this.packages)
+ this.packages=[];
+ if(!this.packages[libraryPackageName]) {
+ this.packages[libraryPackageName] = true;
+ var re = /\./g; // Replace all '.' in package name
+ var packagePath = LibraryPath + libraryPackageName.replace(re, "/");
+ document.write('<script type="text/javascript" src="' + packagePath + '.js"></script>');
+ }
+ },
+ include2: function(libraryPackageName) {
+ if(!this.packages)
+ this.packages=[];
+ if(!this.packages[libraryPackageName]) {
+ this.packages[libraryPackageName] = true;
+ var re = /\./g; // Replace all '.' in package name
+ var packagePath = LibraryPath + libraryPackageName.replace(re, "/");
+ var e = document.createElement("script");
+ e.src = packagePath+".js";
+ e.type="text/javascript";
+ document.getElementsByTagName("head")[0].appendChild(e);
+ }
+ },
+ requireClass: function(libName) {
+ // required class not included before
+ if(!this.packages[libName]) {
+ //this.include2(libName);
+ ClientUILib.log(ClientUILogger.ERROR, "Library '" + libName + "' required!!!");
+ throw("Package '" + libName + "' is required!");
+ }
+ },
+ declarePackage: function(libName) {
+ var pckg = null;
+ var packages = $A(libName.split("."));
+ packages.each( function(s) {
+ if(pckg == null)
+ pckg = eval(s);
+ else {
+ if(!pckg[s]) pckg[s] = {};
+ pckg = pckg[s];
+ }
+ });
+ this.packages[libName] = true;
+ ClientUILib.log(ClientUILogger.INFO, "ClientUILib::declarePackage '" + libName + "'");
+ },
+ log: function(level, infoText) {
+ if(ClientUILogger.isCreated)
+ ClientUILogger.log(level, infoText);
+ },
+ initBrowser: function() {
+ var ua = navigator.userAgent.toLowerCase();
+ /** @type Boolean */
+ this.isOpera = (ua.indexOf('opera') > -1);
+ /** @type Boolean */
+ this.isSafari = (ua.indexOf('webkit') > -1);
+ /** @type Boolean */
+ this.isIE = (window.ActiveXObject);
+ /** @type Boolean */
+ this.isIE7 = (ua.indexOf('msie 7') > -1);
+ /** @type Boolean */
+ this.isGecko = !this.isSafari && (ua.indexOf('gecko') > -1);
+
+ if(ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1){
+ /** @type Boolean */
+ this.isWindows = true;
+ }else if(ua.indexOf("macintosh") != -1){
+ /** @type Boolean */
+ this.isMac = true;
+ }
+ if(this.isIE && !this.isIE7){
+ try{
+ document.execCommand("BackgroundImageCache", false, true);
+ }catch(e){}
+ }
+ }
+};
+
+var ClientUILogger = {
+ // log level
+ INFO: 1,
+ WARNING: 2,
+ ERROR: 3,
+
+ // flag logger is initialized
+ isCreated: false,
+ width: 500,
+ height: 150,
+ create: function() {
+ this.logElement = $(document.createElement("div"));
+ this.logElement.setStyle({position: 'absolute'});
+ this.logElement.setStyle({overflow: 'auto'});
+ this.logElement.setStyle({whiteSpace: 'nowrap'});
+
+ Event.observe(window, 'load', ClientUILogger.init);
+ Event.observe(window, 'resize', ClientUILogger.resizeWindow);
+ this.isCreated = true;
+ },
+ init: function() {
+ if(ClientUILogger.logElement)
+ document.body.appendChild(ClientUILogger.logElement);
+ ClientUILogger.show();
+ },
+ resizeWindow: function() {
+ ClientUILogger.show();
+ },
+ show: function() {
+ if(this.logElement) {
+ Element.show(this.logElement);
+ this.logElement.setStyle({width: this.width + 'px'});
+ this.logElement.setStyle({height: this.height + 'px'});
+ this.logElement.setStyle({top: (this.getWindowHeight() - this.height - 10) + 'px'});
+ this.logElement.setStyle({left: (this.getWindowWidth() - this.width - 10) + 'px'});
+ }
+ },
+ log: function(level, infoText) {
+ var msg = $(document.createElement("div"));
+ this.logElement.appendChild(msg);
+ msg.setStyle({width: '100%'});
+
+ var font = "bold normal bold 10pt Arial";
+ var fontColor = "red";
+
+ switch(level) {
+ case ClientUILogger.INFO:
+ fontColor = "black";
+ font = "normal normal normal 10pt Arial";
+ break;
+ case ClientUILogger.WARNING:
+ fontColor = "blue";
+ font = "italic normal normal 10pt Arial";
+ break;
+ case ClientUILogger.ERROR:
+ fontColor = "red";
+ font = "normal normal bold 10pt Arial";
+ break;
+ default:
+ infoText = "UNRESOLVED: level=" + level + ", msg=" + infoText;
+ }
+ msg.setStyle({font: font});
+ msg.setStyle({color: fontColor});
+ msg.appendChild(document.createTextNode("> " + infoText));
+
+ this.logElement.scrollTop = this.logElement.scrollHeight;
+ },
+ getWindowWidth: function(){
+ var innerWidth;
+ if (navigator.appVersion.indexOf('MSIE')>0) {
+ innerWidth = document.body.clientWidth;
+ } else {
+ innerWidth = window.innerWidth;
+ }
+ return innerWidth;
+ },
+ getWindowHeight: function(){
+ var innerHeight;
+ if (navigator.appVersion.indexOf('MSIE')>0) {
+ innerHeight = document.body.clientHeight;
+ } else {
+ innerHeight = window.innerHeight;
+ }
+ return innerHeight;
+ }
+};
+
+ClientUILib.load(true);
+
+// declare predefined packages
+var ClientUI = {
+ controls: {},
+ layouts: {}
+};
+
Added: trunk/sandbox/scrollable-grid/src/main/javascript/common/prototype/ext/extend.js
===================================================================
--- trunk/sandbox/scrollable-grid/src/main/javascript/common/prototype/ext/extend.js (rev 0)
+++ trunk/sandbox/scrollable-grid/src/main/javascript/common/prototype/ext/extend.js 2007-04-24 15:27:18 UTC (rev 518)
@@ -0,0 +1,186 @@
+// vim: tw=80 ts=4 sw=4 noet
+// ----------------------------------------------------------------------------
+// Project : Extend - Prototype OOP extension
+// URL : <http://www.ivy.fr/js/extend>
+// ----------------------------------------------------------------------------
+// Author : Sebastien Pierre <sebastien(a)ivy.fr>
+// License : Revised BSD License
+// ----------------------------------------------------------------------------
+// Creation : 08-Sep-2006
+// Last mod : 17-Nov-2006
+// ----------------------------------------------------------------------------
+
+// The Extend object holds all the information required to implement the
+// inheritance and other OO-goodness.
+Extend = {
+ VERSION: 1.1,
+ CLASSDEF: "CLASSDEF",
+ DELETE: "DELETE",
+ // These are a list of methods of class instances that are reserved by the
+ // OO layer (see the reparent method for more info)
+ INSTANCE_RESERVED: {
+ CLASSDEF: true,
+ getClass: true,
+ parentClass: true
+ },
+
+ // Sets up a class
+ setupClass: function( _class, declaration )
+ {
+ // We create an empty prototype if the user did not provide one
+ declaration = declaration || {}
+ _class.prototype = declaration
+ // We clone the given method definition, because they will be augmented
+ // with the ones defined in the parent class
+ _class.methods = {}
+ for ( var key in declaration ) { _class.methods[key] = declaration[key] }
+ _class.inherited = {}
+ _class.parentClass = undefined
+ if ( declaration[Extend.CLASSDEF] )
+ { _class.className = declaration[Extend.CLASSDEF].name }
+ else
+ { _class.className = undefined }
+ _class.subclasses = _class.subclasses || []
+ _class.constructor = Extend.Operations.constructor
+ _class.reparent = Extend.Operations.reparent
+ _class.method = Extend.Operations.method
+ _class.update = Extend.Operations.update
+ if ( declaration[Extend.CLASSDEF] )
+ { _class.reparent(declaration[Extend.CLASSDEF].parent) }
+ // We update the class methods with an `ofClass` method that returns the
+ // class, so that instances will have a proper
+ declaration.getClass = function() {return _class}
+ declaration.parentClass = function() {return this.getClass().parentClass}
+ declaration.parentCall = function() {
+ var new_args = []
+ for ( var i=1;i<arguments.length;i++ ) {new_args.push(arguments[i])}
+ return this.parentClass().method(arguments[0]).apply(this, new_args)
+ }
+ declaration.setClass = function(newClass) {
+ return this.getClass().parentClass
+ }
+ // We reparent the subclasses if any
+ for ( var i=0 ; i<_class.subclasses ; i++ ) {
+ _class.subclasses[i].reparent(_class)
+ }
+ return _class
+ },
+ // These are operations that will be "mixed-in" with the new classes
+ Operations: {
+ constructor: function() {
+ return this.prototype.initialize || function() {}
+ },
+ // Reparents this class
+ reparent: function( newParentClass )
+ {
+ if ( this.parentClass )
+ {
+ var this_index = this.subclasses.indexOf(this)
+ this.parentClass.subclasses.splice(this_index, 1)
+ for ( var method_name in this.inherited ) {
+ this.method(method_name, null, this.parentClass)
+ }
+ }
+ this.parentClass = newParentClass
+ if ( !newParentClass ) return
+ var parent_methods = newParentClass.prototype
+ // We iterate on all the parent methods
+ for ( parent_method_name in parent_methods ) {
+ // If the method is a reserved one, we skip it
+ if ( Extend.INSTANCE_RESERVED[parent_method_name] == true ) { continue }
+ // If the method is not directly defined in the current class, we add it
+ if ( this.methods[parent_method_name] == undefined )
+ {
+ this.method( parent_method_name,
+ parent_methods[parent_method_name],
+ newParentClass.inherited[parent_method_name] || newParentClass
+ )
+ }
+ }
+ newParentClass.subclasses.push(this)
+ },
+ update: function(newPrototype) {
+ Extend.setupClass(this, newPrototype||this.prototype)
+ },
+ // Returns, sets or deletes a method in this class
+ method: function( name, body, declaredIn ) {
+ if ( body == undefined )
+ {
+ var method = this.prototype[name]
+ if ( name == undefined ) throw new Error("Method not found: "+name)
+ return method
+ }
+ else
+ {
+ declaredIn = declaredIn || this
+ // If the method is declared in this class
+ if ( declaredIn == this )
+ {
+ if ( body == Extend.DELETE ) {
+ delete this.methods[name]
+ delete this.inherited[name]
+ delete this.prototype[name]
+ // If the method is defined in the parent we set it
+ if ( this.parentClass ) {
+ var parent_method = this.parentClass.method(name)
+ if ( parent_method ) {
+ this.method(name, parent_method, this.parentClass.inherited[name] || this.parentClass)
+ }
+ }
+ } else {
+ this.methods[name] = body
+ this.prototype[name] = body
+ delete this.inherited[name]
+ }
+ }
+ // Or if its declared in another class
+ else
+ {
+ if ( body == Extend.DELETE ) {
+ delete this.inherited[name]
+ delete this.methods[name]
+ delete this.prototype[name]
+ // If the method is defined in the parent we set it
+ if ( this.parentClass ) {
+ var parent_method = this.parentClass.method(name)
+ if ( parent_method ) {
+ this.method(name, parent_method, this.parentClass.inherited[name] || this.parentClass)
+ }
+ }
+ }
+ else {
+ if ( this.methods[name] == undefined ) {
+ this.inherited[name] = declaredIn
+ this.prototype[name] = body
+ }
+ }
+ }
+ for ( var i=0 ; i<this.subclasses.length ; i++ )
+ {
+ this.subclasses[i].method(name,body,declaredIn)
+ }
+ }
+ }
+ }
+}
+
+// In case prototype is not available, we use this instead
+try {
+ Class = Class
+} catch ( Error ) {
+ Class = {create:function() {return function() {this.initialize.apply(this, arguments)}}}
+}
+Class._create = Class.create
+Class.create = function( declaration ) {
+ var new_class = Extend.setupClass(Class._create(declaration), declaration)
+ // The following only works on FireFox
+ /*
+ new_class.watch("prototype", function(id,oldval,newval) {
+ new_class.prototype = newval
+ Extend.setupClass(new_class, newval)
+ return newval
+ })*/
+ return new_class
+}
+
+// EOF
Added: trunk/sandbox/scrollable-grid/src/main/javascript/common/prototype/prototype.js
===================================================================
--- trunk/sandbox/scrollable-grid/src/main/javascript/common/prototype/prototype.js (rev 0)
+++ trunk/sandbox/scrollable-grid/src/main/javascript/common/prototype/prototype.js 2007-04-24 15:27:18 UTC (rev 518)
@@ -0,0 +1,2515 @@
+/* Prototype JavaScript framework, version 1.5.0
+ * (c) 2005-2007 Sam Stephenson
+ *
+ * Prototype is freely distributable under the terms of an MIT-style license.
+ * For details, see the Prototype web site: http://prototype.conio.net/
+ *
+/*--------------------------------------------------------------------------*/
+
+var Prototype = {
+ Version: '1.5.0',
+ BrowserFeatures: {
+ XPath: !!document.evaluate
+ },
+
+ ScriptFragment: '(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)',
+ emptyFunction: function() {},
+ K: function(x) { return x }
+}
+
+var Class = {
+ create: function() {
+ return function() {
+ this.initialize.apply(this, arguments);
+ }
+ }
+}
+
+var Abstract = new Object();
+
+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 === undefined) return 'undefined';
+ if (object === null) return 'null';
+ return object.inspect ? object.inspect() : object.toString();
+ } catch (e) {
+ if (e instanceof RangeError) return '...';
+ throw e;
+ }
+ },
+
+ 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);
+ }
+});
+
+Function.prototype.bind = function() {
+ var __method = this, args = $A(arguments), object = args.shift();
+ return function() {
+ return __method.apply(object, args.concat($A(arguments)));
+ }
+}
+
+Function.prototype.bindAsEventListener = function(object) {
+ var __method = this, args = $A(arguments), object = args.shift();
+ return function(event) {
+ return __method.apply(object, [( event || window.event)].concat(args).concat($A(arguments)));
+ }
+}
+
+Object.extend(Number.prototype, {
+ toColorPart: function() {
+ var digits = this.toString(16);
+ if (this < 16) return '0' + digits;
+ return digits;
+ },
+
+ succ: function() {
+ return this + 1;
+ },
+
+ times: function(iterator) {
+ $R(0, this, true).each(iterator);
+ return this;
+ }
+});
+
+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;
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+
+var PeriodicalExecuter = Class.create();
+PeriodicalExecuter.prototype = {
+ 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);
+ },
+
+ stop: function() {
+ if (!this.timer) return;
+ clearInterval(this.timer);
+ this.timer = null;
+ },
+
+ onTimerEvent: function() {
+ if (!this.currentlyExecuting) {
+ try {
+ this.currentlyExecuting = true;
+ this.callback(this);
+ } finally {
+ this.currentlyExecuting = false;
+ }
+ }
+ }
+}
+String.interpret = function(value){
+ return value == null ? '' : String(value);
+}
+
+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 = count === undefined ? 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 this;
+ },
+
+ truncate: function(length, truncation) {
+ length = length || 30;
+ truncation = truncation === undefined ? '...' : truncation;
+ return this.length > length ?
+ this.slice(0, length - truncation.length) + truncation : 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 div = document.createElement('div');
+ var text = document.createTextNode(this);
+ div.appendChild(text);
+ return div.innerHTML;
+ },
+
+ unescapeHTML: function() {
+ var div = document.createElement('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 name = decodeURIComponent(pair[0]);
+ var value = pair[1] ? decodeURIComponent(pair[1]) : undefined;
+
+ if (hash[name] !== undefined) {
+ if (hash[name].constructor != Array)
+ hash[name] = [hash[name]];
+ if (value) hash[name].push(value);
+ }
+ else hash[name] = 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);
+ },
+
+ 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.replace(/\\/g, '\\\\');
+ if (useDoubleQuotes)
+ return '"' + escapedString.replace(/"/g, '\\"') + '"';
+ else
+ return "'" + escapedString.replace(/'/g, '\\\'') + "'";
+ }
+});
+
+String.prototype.gsub.prepareReplacement = function(replacement) {
+ if (typeof replacement == 'function') return replacement;
+ var template = new Template(replacement);
+ return function(match) { return template.evaluate(match) };
+}
+
+String.prototype.parseQuery = String.prototype.toQueryParams;
+
+var Template = Class.create();
+Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;
+Template.prototype = {
+ initialize: function(template, pattern) {
+ this.template = template.toString();
+ this.pattern = pattern || Template.Pattern;
+ },
+
+ evaluate: function(object) {
+ return this.template.gsub(this.pattern, function(match) {
+ var before = match[1];
+ if (before == '\\') return match[2];
+ return before + String.interpret(object[match[3]]);
+ });
+ }
+}
+
+var $break = new Object();
+var $continue = new Object();
+
+var Enumerable = {
+ each: function(iterator) {
+ var index = 0;
+ try {
+ this._each(function(value) {
+ try {
+ iterator(value, index++);
+ } catch (e) {
+ if (e != $continue) throw e;
+ }
+ });
+ } catch (e) {
+ if (e != $break) throw e;
+ }
+ return this;
+ },
+
+ eachSlice: function(number, iterator) {
+ var index = -number, slices = [], array = this.toArray();
+ while ((index += number) < array.length)
+ slices.push(array.slice(index, index+number));
+ return slices.map(iterator);
+ },
+
+ all: function(iterator) {
+ var result = true;
+ this.each(function(value, index) {
+ result = result && !!(iterator || Prototype.K)(value, index);
+ if (!result) throw $break;
+ });
+ return result;
+ },
+
+ any: function(iterator) {
+ var result = false;
+ this.each(function(value, index) {
+ if (result = !!(iterator || Prototype.K)(value, index))
+ throw $break;
+ });
+ return result;
+ },
+
+ collect: function(iterator) {
+ var results = [];
+ this.each(function(value, index) {
+ results.push((iterator || Prototype.K)(value, index));
+ });
+ return results;
+ },
+
+ detect: function(iterator) {
+ var result;
+ this.each(function(value, index) {
+ if (iterator(value, index)) {
+ result = value;
+ throw $break;
+ }
+ });
+ return result;
+ },
+
+ findAll: function(iterator) {
+ var results = [];
+ this.each(function(value, index) {
+ if (iterator(value, index))
+ results.push(value);
+ });
+ return results;
+ },
+
+ grep: function(pattern, iterator) {
+ var results = [];
+ this.each(function(value, index) {
+ var stringValue = value.toString();
+ if (stringValue.match(pattern))
+ results.push((iterator || Prototype.K)(value, index));
+ })
+ return results;
+ },
+
+ include: function(object) {
+ var found = false;
+ this.each(function(value) {
+ if (value == object) {
+ found = true;
+ throw $break;
+ }
+ });
+ return found;
+ },
+
+ inGroupsOf: function(number, fillWith) {
+ fillWith = fillWith === undefined ? null : fillWith;
+ return this.eachSlice(number, function(slice) {
+ while(slice.length < number) slice.push(fillWith);
+ return slice;
+ });
+ },
+
+ inject: function(memo, iterator) {
+ 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) {
+ var result;
+ this.each(function(value, index) {
+ value = (iterator || Prototype.K)(value, index);
+ if (result == undefined || value >= result)
+ result = value;
+ });
+ return result;
+ },
+
+ min: function(iterator) {
+ var result;
+ this.each(function(value, index) {
+ value = (iterator || Prototype.K)(value, index);
+ if (result == undefined || value < result)
+ result = value;
+ });
+ return result;
+ },
+
+ partition: function(iterator) {
+ var trues = [], falses = [];
+ this.each(function(value, index) {
+ ((iterator || Prototype.K)(value, index) ?
+ trues : falses).push(value);
+ });
+ return [trues, falses];
+ },
+
+ pluck: function(property) {
+ var results = [];
+ this.each(function(value, index) {
+ results.push(value[property]);
+ });
+ return results;
+ },
+
+ reject: function(iterator) {
+ var results = [];
+ this.each(function(value, index) {
+ if (!iterator(value, index))
+ results.push(value);
+ });
+ return results;
+ },
+
+ sortBy: function(iterator) {
+ 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 (typeof args.last() == 'function')
+ 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,
+ member: Enumerable.include,
+ entries: Enumerable.toArray
+});
+var $A = Array.from = function(iterable) {
+ if (!iterable) return [];
+ if (iterable.toArray) {
+ return iterable.toArray();
+ } else {
+ var results = [];
+ for (var i = 0, length = iterable.length; i < length; i++)
+ results.push(iterable[i]);
+ return results;
+ }
+}
+
+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(value && value.constructor == Array ?
+ value.flatten() : [value]);
+ });
+ },
+
+ without: function() {
+ var values = $A(arguments);
+ return this.select(function(value) {
+ return !values.include(value);
+ });
+ },
+
+ indexOf: function(object) {
+ for (var i = 0, length = this.length; i < length; i++)
+ if (this[i] == object) return i;
+ return -1;
+ },
+
+ reverse: function(inline) {
+ return (inline !== false ? this : this.toArray())._reverse();
+ },
+
+ reduce: function() {
+ return this.length > 1 ? this : this[0];
+ },
+
+ uniq: function() {
+ return this.inject([], function(array, value) {
+ return array.include(value) ? array : array.concat([value]);
+ });
+ },
+
+ clone: function() {
+ return [].concat(this);
+ },
+
+ size: function() {
+ return this.length;
+ },
+
+ inspect: function() {
+ return '[' + this.map(Object.inspect).join(', ') + ']';
+ }
+});
+
+Array.prototype.toArray = Array.prototype.clone;
+
+function $w(string){
+ string = string.strip();
+ return string ? string.split(/\s+/) : [];
+}
+
+if(window.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(arguments[i].constructor == Array) {
+ for(var j = 0, arrayLength = arguments[i].length; j < arrayLength; j++)
+ array.push(arguments[i][j]);
+ } else {
+ array.push(arguments[i]);
+ }
+ }
+ return array;
+ }
+}
+var Hash = function(obj) {
+ Object.extend(this, obj || {});
+};
+
+Object.extend(Hash, {
+ toQueryString: function(obj) {
+ var parts = [];
+
+ this.prototype._each.call(obj, function(pair) {
+ if (!pair.key) return;
+
+ if (pair.value && pair.value.constructor == Array) {
+ var values = pair.value.compact();
+ if (values.length < 2) pair.value = values.reduce();
+ else {
+ key = encodeURIComponent(pair.key);
+ values.each(function(value) {
+ value = value != undefined ? encodeURIComponent(value) : '';
+ parts.push(key + '=' + encodeURIComponent(value));
+ });
+ return;
+ }
+ }
+ if (pair.value == undefined) pair[1] = '';
+ parts.push(pair.map(encodeURIComponent).join('='));
+ });
+
+ return parts.join('&');
+ }
+});
+
+Object.extend(Hash.prototype, Enumerable);
+Object.extend(Hash.prototype, {
+ _each: function(iterator) {
+ for (var key in this) {
+ var value = this[key];
+ if (value && value == Hash.prototype[key]) continue;
+
+ var pair = [key, value];
+ pair.key = key;
+ pair.value = value;
+ iterator(pair);
+ }
+ },
+
+ keys: function() {
+ return this.pluck('key');
+ },
+
+ values: function() {
+ return this.pluck('value');
+ },
+
+ merge: function(hash) {
+ return $H(hash).inject(this, function(mergedHash, pair) {
+ mergedHash[pair.key] = pair.value;
+ return mergedHash;
+ });
+ },
+
+ remove: function() {
+ var result;
+ for(var i = 0, length = arguments.length; i < length; i++) {
+ var value = this[arguments[i]];
+ if (value !== undefined){
+ if (result === undefined) result = value;
+ else {
+ if (result.constructor != Array) result = [result];
+ result.push(value)
+ }
+ }
+ delete this[arguments[i]];
+ }
+ return result;
+ },
+
+ toQueryString: function() {
+ return Hash.toQueryString(this);
+ },
+
+ inspect: function() {
+ return '#<Hash:{' + this.map(function(pair) {
+ return pair.map(Object.inspect).join(': ');
+ }).join(', ') + '}>';
+ }
+});
+
+function $H(object) {
+ if (object && object.constructor == Hash) return object;
+ return new Hash(object);
+};
+ObjectRange = Class.create();
+Object.extend(ObjectRange.prototype, Enumerable);
+Object.extend(ObjectRange.prototype, {
+ 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 (typeof responder[callback] == 'function') {
+ 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 = function() {};
+Ajax.Base.prototype = {
+ setOptions: function(options) {
+ this.options = {
+ method: 'post',
+ asynchronous: true,
+ contentType: 'application/x-www-form-urlencoded',
+ encoding: 'UTF-8',
+ parameters: ''
+ }
+ Object.extend(this.options, options || {});
+
+ this.options.method = this.options.method.toLowerCase();
+ if (typeof this.options.parameters == 'string')
+ this.options.parameters = this.options.parameters.toQueryParams();
+ }
+}
+
+Ajax.Request = Class.create();
+Ajax.Request.Events =
+ ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
+
+Ajax.Request.prototype = Object.extend(new Ajax.Base(), {
+ _complete: false,
+
+ initialize: function(url, options) {
+ this.transport = Ajax.getTransport();
+ this.setOptions(options);
+ this.request(url);
+ },
+
+ request: function(url) {
+ this.url = url;
+ this.method = this.options.method;
+ var params = this.options.parameters;
+
+ if (!['get', 'post'].include(this.method)) {
+ // simulate other verbs over post
+ params['_method'] = this.method;
+ this.method = 'post';
+ }
+
+ params = Hash.toQueryString(params);
+ if (params && /Konqueror|Safari|KHTML/.test(navigator.userAgent)) params += '&_='
+
+ // when GET, append parameters to URL
+ if (this.method == 'get' && params)
+ this.url += (this.url.indexOf('?') > -1 ? '&' : '?') + params;
+
+ try {
+ Ajax.Responders.dispatch('onCreate', this, this.transport);
+
+ this.transport.open(this.method.toUpperCase(), this.url,
+ this.options.asynchronous);
+
+ if (this.options.asynchronous)
+ setTimeout(function() { this.respondToReadyState(1) }.bind(this), 10);
+
+ this.transport.onreadystatechange = this.onStateChange.bind(this);
+ this.setRequestHeaders();
+
+ var body = this.method == 'post' ? (this.options.postBody || params) : null;
+
+ this.transport.send(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 (typeof extras.push == 'function')
+ 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() {
+ return !this.transport.status
+ || (this.transport.status >= 200 && this.transport.status < 300);
+ },
+
+ respondToReadyState: function(readyState) {
+ var state = Ajax.Request.Events[readyState];
+ var transport = this.transport, json = this.evalJSON();
+
+ if (state == 'Complete') {
+ try {
+ this._complete = true;
+ (this.options['on' + this.transport.status]
+ || this.options['on' + (this.success() ? 'Success' : 'Failure')]
+ || Prototype.emptyFunction)(transport, json);
+ } catch (e) {
+ this.dispatchException(e);
+ }
+
+ if ((this.getHeader('Content-type') || 'text/javascript').strip().
+ match(/^(text|application)\/(x-)?(java|ecma)script(;.*)?$/i))
+ this.evalResponse();
+ }
+
+ try {
+ (this.options['on' + state] || Prototype.emptyFunction)(transport, json);
+ Ajax.Responders.dispatch('on' + state, this, transport, json);
+ } catch (e) {
+ this.dispatchException(e);
+ }
+
+ if (state == 'Complete') {
+ // avoid memory leak in MSIE: clean up
+ this.transport.onreadystatechange = Prototype.emptyFunction;
+ }
+ },
+
+ getHeader: function(name) {
+ try {
+ return this.transport.getResponseHeader(name);
+ } catch (e) { return null }
+ },
+
+ evalJSON: function() {
+ try {
+ var json = this.getHeader('X-JSON');
+ return json ? eval('(' + json + ')') : null;
+ } catch (e) { return null }
+ },
+
+ evalResponse: function() {
+ try {
+ return eval(this.transport.responseText);
+ } catch (e) {
+ this.dispatchException(e);
+ }
+ },
+
+ dispatchException: function(exception) {
+ (this.options.onException || Prototype.emptyFunction)(this, exception);
+ Ajax.Responders.dispatch('onException', this, exception);
+ }
+});
+
+Ajax.Updater = Class.create();
+
+Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), {
+ initialize: function(container, url, options) {
+ this.container = {
+ success: (container.success || container),
+ failure: (container.failure || (container.success ? null : container))
+ }
+
+ this.transport = Ajax.getTransport();
+ this.setOptions(options);
+
+ var onComplete = this.options.onComplete || Prototype.emptyFunction;
+ this.options.onComplete = (function(transport, param) {
+ this.updateContent();
+ onComplete(transport, param);
+ }).bind(this);
+
+ this.request(url);
+ },
+
+ updateContent: function() {
+ var receiver = this.container[this.success() ? 'success' : 'failure'];
+ var response = this.transport.responseText;
+
+ if (!this.options.evalScripts) response = response.stripScripts();
+
+ if (receiver = $(receiver)) {
+ if (this.options.insertion)
+ new this.options.insertion(receiver, response);
+ else
+ receiver.update(response);
+ }
+
+ if (this.success()) {
+ if (this.onComplete)
+ setTimeout(this.onComplete.bind(this), 10);
+ }
+ }
+});
+
+Ajax.PeriodicalUpdater = Class.create();
+Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), {
+ initialize: function(container, url, options) {
+ this.setOptions(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(request) {
+ if (this.options.decay) {
+ this.decay = (request.responseText == this.lastText ?
+ this.decay * this.options.decay : 1);
+
+ this.lastText = request.responseText;
+ }
+ this.timer = setTimeout(this.onTimerEvent.bind(this),
+ this.decay * this.frequency * 1000);
+ },
+
+ 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 (typeof element == 'string')
+ 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(query.snapshotItem(i));
+ return results;
+ };
+}
+
+document.getElementsByClassName = function(className, parentElement) {
+ if (Prototype.BrowserFeatures.XPath) {
+ var q = ".//*[contains(concat(' ', @class, ' '), ' " + className + " ')]";
+ return document._getElementsByXPath(q, parentElement);
+ } else {
+ var children = ($(parentElement) || document.body).getElementsByTagName('*');
+ var elements = [], child;
+ for (var i = 0, length = children.length; i < length; i++) {
+ child = children[i];
+ if (Element.hasClassName(child, className))
+ elements.push(Element.extend(child));
+ }
+ return elements;
+ }
+};
+
+/*--------------------------------------------------------------------------*/
+
+if (!window.Element)
+ var Element = new Object();
+
+Element.extend = function(element) {
+ if (!element || _nativeExtensions || element.nodeType == 3) return element;
+
+ if (!element._extended && element.tagName && element != window) {
+ var methods = Object.clone(Element.Methods), cache = Element.extend.cache;
+
+ if (element.tagName == 'FORM')
+ Object.extend(methods, Form.Methods);
+ if (['INPUT', 'TEXTAREA', 'SELECT'].include(element.tagName))
+ Object.extend(methods, Form.Element.Methods);
+
+ Object.extend(methods, Element.Methods.Simulated);
+
+ for (var property in methods) {
+ var value = methods[property];
+ if (typeof value == 'function' && !(property in element))
+ element[property] = cache.findOrStore(value);
+ }
+ }
+
+ element._extended = true;
+ return element;
+};
+
+Element.extend.cache = {
+ findOrStore: function(value) {
+ return this[value] = this[value] || function() {
+ return value.apply(null, [this].concat($A(arguments)));
+ }
+ }
+};
+
+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, html) {
+ html = typeof html == 'undefined' ? '' : html.toString();
+ $(element).innerHTML = html.stripScripts();
+ setTimeout(function() {html.evalScripts()}, 10);
+ return element;
+ },
+
+ replace: function(element, html) {
+ element = $(element);
+ html = typeof html == 'undefined' ? '' : html.toString();
+ if (element.outerHTML) {
+ element.outerHTML = html.stripScripts();
+ } else {
+ var range = element.ownerDocument.createRange();
+ range.selectNodeContents(element);
+ element.parentNode.replaceChild(
+ range.createContextualFragment(html.stripScripts()), element);
+ }
+ setTimeout(function() {html.evalScripts()}, 10);
+ return element;
+ },
+
+ 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 $A($(element).getElementsByTagName('*'));
+ },
+
+ 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 (typeof selector == 'string')
+ selector = new Selector(selector);
+ return selector.match($(element));
+ },
+
+ up: function(element, expression, index) {
+ return Selector.findElement($(element).ancestors(), expression, index);
+ },
+
+ down: function(element, expression, index) {
+ return Selector.findElement($(element).descendants(), expression, index);
+ },
+
+ previous: function(element, expression, index) {
+ return Selector.findElement($(element).previousSiblings(), expression, index);
+ },
+
+ next: function(element, expression, index) {
+ return Selector.findElement($(element).nextSiblings(), expression, index);
+ },
+
+ getElementsBySelector: function() {
+ var args = $A(arguments), element = $(args.shift());
+ return Selector.findChildElements(element, args);
+ },
+
+ getElementsByClassName: function(element, className) {
+ return document.getElementsByClassName(className, element);
+ },
+
+ readAttribute: function(element, name) {
+ element = $(element);
+ if (document.all && !window.opera) {
+ var t = Element._attributeTranslations;
+ if (t.values[name]) return t.values[name](element, name);
+ if (t.names[name]) name = t.names[name];
+ var attribute = element.attributes[name];
+ if(attribute) return attribute.nodeValue;
+ }
+ return element.getAttribute(name);
+ },
+
+ 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;
+ if (elementClassName.length == 0) return false;
+ if (elementClassName == className ||
+ elementClassName.match(new RegExp("(^|\\s)" + className + "(\\s|$)")))
+ return true;
+ return false;
+ },
+
+ addClassName: function(element, className) {
+ if (!(element = $(element))) return;
+ Element.classNames(element).add(className);
+ return element;
+ },
+
+ removeClassName: function(element, className) {
+ if (!(element = $(element))) return;
+ Element.classNames(element).remove(className);
+ return element;
+ },
+
+ toggleClassName: function(element, className) {
+ if (!(element = $(element))) return;
+ Element.classNames(element)[element.hasClassName(className) ? 'remove' : 'add'](className);
+ return element;
+ },
+
+ observe: function() {
+ Event.observe.apply(Event, arguments);
+ return $A(arguments).first();
+ },
+
+ stopObserving: function() {
+ Event.stopObserving.apply(Event, arguments);
+ return $A(arguments).first();
+ },
+
+ // 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.match(/^\s*$/);
+ },
+
+ descendantOf: function(element, ancestor) {
+ element = $(element), ancestor = $(ancestor);
+ while (element = element.parentNode)
+ if (element == ancestor) return true;
+ return false;
+ },
+
+ scrollTo: function(element) {
+ element = $(element);
+ var pos = Position.cumulativeOffset(element);
+ window.scrollTo(pos[0], pos[1]);
+ return element;
+ },
+
+ getStyle: function(element, style) {
+ element = $(element);
+ if (['float','cssFloat'].include(style))
+ style = (typeof element.style.styleFloat != 'undefined' ? 'styleFloat' : 'cssFloat');
+ style = style.camelize();
+ var value = element.style[style];
+ if (!value) {
+ if (document.defaultView && document.defaultView.getComputedStyle) {
+ var css = document.defaultView.getComputedStyle(element, null);
+ value = css ? css[style] : null;
+ } else if (element.currentStyle) {
+ value = element.currentStyle[style];
+ }
+ }
+
+ if((value == 'auto') && ['width','height'].include(style) && (element.getStyle('display') != 'none'))
+ value = element['offset'+style.capitalize()] + 'px';
+
+ if (window.opera && ['left', 'top', 'right', 'bottom'].include(style))
+ if (Element.getStyle(element, 'position') == 'static') value = 'auto';
+ if(style == 'opacity') {
+ if(value) return parseFloat(value);
+ if(value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/))
+ if(value[1]) return parseFloat(value[1]) / 100;
+ return 1.0;
+ }
+ return value == 'auto' ? null : value;
+ },
+
+ setStyle: function(element, style) {
+ element = $(element);
+ for (var name in style) {
+ var value = style[name];
+ if(name == 'opacity') {
+ if (value == 1) {
+ value = (/Gecko/.test(navigator.userAgent) &&
+ !/Konqueror|Safari|KHTML/.test(navigator.userAgent)) ? 0.999999 : 1.0;
+ if(/MSIE/.test(navigator.userAgent) && !window.opera)
+ element.style.filter = element.getStyle('filter').replace(/alpha\([^\)]*\)/gi,'');
+ } else if(value == '') {
+ if(/MSIE/.test(navigator.userAgent) && !window.opera)
+ element.style.filter = element.getStyle('filter').replace(/alpha\([^\)]*\)/gi,'');
+ } else {
+ if(value < 0.00001) value = 0;
+ if(/MSIE/.test(navigator.userAgent) && !window.opera)
+ element.style.filter = element.getStyle('filter').replace(/alpha\([^\)]*\)/gi,'') +
+ 'alpha(opacity='+value*100+')';
+ }
+ } else if(['float','cssFloat'].include(name)) name = (typeof element.style.styleFloat != 'undefined') ? 'styleFloat' : 'cssFloat';
+ element.style[name.camelize()] = 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.style.overflow || 'auto';
+ if ((Element.getStyle(element, 'overflow') || 'visible') != '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;
+ }
+};
+
+Object.extend(Element.Methods, {childOf: Element.Methods.descendantOf});
+
+Element._attributeTranslations = {};
+
+Element._attributeTranslations.names = {
+ colspan: "colSpan",
+ rowspan: "rowSpan",
+ valign: "vAlign",
+ datetime: "dateTime",
+ accesskey: "accessKey",
+ tabindex: "tabIndex",
+ enctype: "encType",
+ maxlength: "maxLength",
+ readonly: "readOnly",
+ longdesc: "longDesc"
+};
+
+Element._attributeTranslations.values = {
+ _getAttr: function(element, attribute) {
+ return element.getAttribute(attribute, 2);
+ },
+
+ _flag: function(element, attribute) {
+ return $(element).hasAttribute(attribute) ? attribute : null;
+ },
+
+ style: function(element) {
+ return element.style.cssText.toLowerCase();
+ },
+
+ title: function(element) {
+ var node = element.getAttributeNode('title');
+ return node.specified ? node.nodeValue : null;
+ }
+};
+
+Object.extend(Element._attributeTranslations.values, {
+ href: Element._attributeTranslations.values._getAttr,
+ src: Element._attributeTranslations.values._getAttr,
+ disabled: Element._attributeTranslations.values._flag,
+ checked: Element._attributeTranslations.values._flag,
+ readonly: Element._attributeTranslations.values._flag,
+ multiple: Element._attributeTranslations.values._flag
+});
+
+Element.Methods.Simulated = {
+ hasAttribute: function(element, attribute) {
+ var t = Element._attributeTranslations;
+ attribute = t.names[attribute] || attribute;
+ return $(element).getAttributeNode(attribute).specified;
+ }
+};
+
+// IE is missing .innerHTML support for TABLE-related elements
+if (document.all && !window.opera){
+ Element.Methods.update = function(element, html) {
+ element = $(element);
+ html = typeof html == 'undefined' ? '' : html.toString();
+ var tagName = element.tagName.toUpperCase();
+ if (['THEAD','TBODY','TR','TD'].include(tagName)) {
+ var div = document.createElement('div');
+ switch (tagName) {
+ case 'THEAD':
+ case 'TBODY':
+ div.innerHTML = '<table><tbody>' + html.stripScripts() + '</tbody></table>';
+ depth = 2;
+ break;
+ case 'TR':
+ div.innerHTML = '<table><tbody><tr>' + html.stripScripts() + '</tr></tbody></table>';
+ depth = 3;
+ break;
+ case 'TD':
+ div.innerHTML = '<table><tbody><tr><td>' + html.stripScripts() + '</td></tr></tbody></table>';
+ depth = 4;
+ }
+ $A(element.childNodes).each(function(node){
+ element.removeChild(node)
+ });
+ depth.times(function(){ div = div.firstChild });
+
+ $A(div.childNodes).each(
+ function(node){ element.appendChild(node) });
+ } else {
+ element.innerHTML = html.stripScripts();
+ }
+ setTimeout(function() {html.evalScripts()}, 10);
+ return element;
+ }
+};
+
+Object.extend(Element, Element.Methods);
+
+var _nativeExtensions = false;
+
+if(/Konqueror|Safari|KHTML/.test(navigator.userAgent))
+ ['', 'Form', 'Input', 'TextArea', 'Select'].each(function(tag) {
+ var className = 'HTML' + tag + 'Element';
+ if(window[className]) return;
+ var klass = window[className] = {};
+ klass.prototype = document.createElement(tag ? tag.toLowerCase() : 'div').__proto__;
+ });
+
+Element.addMethods = function(methods) {
+ Object.extend(Element.Methods, methods || {});
+
+ function copy(methods, destination, onlyIfAbsent) {
+ onlyIfAbsent = onlyIfAbsent || false;
+ var cache = Element.extend.cache;
+ for (var property in methods) {
+ var value = methods[property];
+ if (!onlyIfAbsent || !(property in destination))
+ destination[property] = cache.findOrStore(value);
+ }
+ }
+
+ if (typeof HTMLElement != 'undefined') {
+ copy(Element.Methods, HTMLElement.prototype);
+ copy(Element.Methods.Simulated, HTMLElement.prototype, true);
+ copy(Form.Methods, HTMLFormElement.prototype);
+ [HTMLInputElement, HTMLTextAreaElement, HTMLSelectElement].each(function(klass) {
+ copy(Form.Element.Methods, klass.prototype);
+ });
+ _nativeExtensions = true;
+ }
+}
+
+var Toggle = new Object();
+Toggle.display = Element.toggle;
+
+/*--------------------------------------------------------------------------*/
+
+Abstract.Insertion = function(adjacency) {
+ this.adjacency = adjacency;
+}
+
+Abstract.Insertion.prototype = {
+ initialize: function(element, content) {
+ this.element = $(element);
+ this.content = content.stripScripts();
+
+ if (this.adjacency && this.element.insertAdjacentHTML) {
+ try {
+ this.element.insertAdjacentHTML(this.adjacency, this.content);
+ } catch (e) {
+ var tagName = this.element.tagName.toUpperCase();
+ if (['TBODY', 'TR'].include(tagName)) {
+ this.insertContent(this.contentFromAnonymousTable());
+ } else {
+ throw e;
+ }
+ }
+ } else {
+ this.range = this.element.ownerDocument.createRange();
+ if (this.initializeRange) this.initializeRange();
+ this.insertContent([this.range.createContextualFragment(this.content)]);
+ }
+
+ setTimeout(function() {content.evalScripts()}, 10);
+ },
+
+ contentFromAnonymousTable: function() {
+ var div = document.createElement('div');
+ div.innerHTML = '<table><tbody>' + this.content + '</tbody></table>';
+ return $A(div.childNodes[0].childNodes[0].childNodes);
+ }
+}
+
+var Insertion = new Object();
+
+Insertion.Before = Class.create();
+Insertion.Before.prototype = Object.extend(new Abstract.Insertion('beforeBegin'), {
+ initializeRange: function() {
+ this.range.setStartBefore(this.element);
+ },
+
+ insertContent: function(fragments) {
+ fragments.each((function(fragment) {
+ this.element.parentNode.insertBefore(fragment, this.element);
+ }).bind(this));
+ }
+});
+
+Insertion.Top = Class.create();
+Insertion.Top.prototype = Object.extend(new Abstract.Insertion('afterBegin'), {
+ initializeRange: function() {
+ this.range.selectNodeContents(this.element);
+ this.range.collapse(true);
+ },
+
+ insertContent: function(fragments) {
+ fragments.reverse(false).each((function(fragment) {
+ this.element.insertBefore(fragment, this.element.firstChild);
+ }).bind(this));
+ }
+});
+
+Insertion.Bottom = Class.create();
+Insertion.Bottom.prototype = Object.extend(new Abstract.Insertion('beforeEnd'), {
+ initializeRange: function() {
+ this.range.selectNodeContents(this.element);
+ this.range.collapse(this.element);
+ },
+
+ insertContent: function(fragments) {
+ fragments.each((function(fragment) {
+ this.element.appendChild(fragment);
+ }).bind(this));
+ }
+});
+
+Insertion.After = Class.create();
+Insertion.After.prototype = Object.extend(new Abstract.Insertion('afterEnd'), {
+ initializeRange: function() {
+ this.range.setStartAfter(this.element);
+ },
+
+ insertContent: function(fragments) {
+ fragments.each((function(fragment) {
+ this.element.parentNode.insertBefore(fragment,
+ this.element.nextSibling);
+ }).bind(this));
+ }
+});
+
+/*--------------------------------------------------------------------------*/
+
+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);
+var Selector = Class.create();
+Selector.prototype = {
+ initialize: function(expression) {
+ this.params = {classNames: []};
+ this.expression = expression.toString().strip();
+ this.parseExpression();
+ this.compileMatcher();
+ },
+
+ parseExpression: function() {
+ function abort(message) { throw 'Parse error in selector: ' + message; }
+
+ if (this.expression == '') abort('empty expression');
+
+ var params = this.params, expr = this.expression, match, modifier, clause, rest;
+ while (match = expr.match(/^(.*)\[([a-z0-9_:-]+?)(?:([~\|!]?=)(?:"([^"]*)"|([^\]\s]*)))?\]$/i)) {
+ params.attributes = params.attributes || [];
+ params.attributes.push({name: match[2], operator: match[3], value: match[4] || match[5] || ''});
+ expr = match[1];
+ }
+
+ if (expr == '*') return this.params.wildcard = true;
+
+ while (match = expr.match(/^([^a-z0-9_-])?([a-z0-9_-]+)(.*)/i)) {
+ modifier = match[1], clause = match[2], rest = match[3];
+ switch (modifier) {
+ case '#': params.id = clause; break;
+ case '.': params.classNames.push(clause); break;
+ case '':
+ case undefined: params.tagName = clause.toUpperCase(); break;
+ default: abort(expr.inspect());
+ }
+ expr = rest;
+ }
+
+ if (expr.length > 0) abort(expr.inspect());
+ },
+
+ buildMatchExpression: function() {
+ var params = this.params, conditions = [], clause;
+
+ if (params.wildcard)
+ conditions.push('true');
+ if (clause = params.id)
+ conditions.push('element.readAttribute("id") == ' + clause.inspect());
+ if (clause = params.tagName)
+ conditions.push('element.tagName.toUpperCase() == ' + clause.inspect());
+ if ((clause = params.classNames).length > 0)
+ for (var i = 0, length = clause.length; i < length; i++)
+ conditions.push('element.hasClassName(' + clause[i].inspect() + ')');
+ if (clause = params.attributes) {
+ clause.each(function(attribute) {
+ var value = 'element.readAttribute(' + attribute.name.inspect() + ')';
+ var splitValueBy = function(delimiter) {
+ return value + ' && ' + value + '.split(' + delimiter.inspect() + ')';
+ }
+
+ switch (attribute.operator) {
+ case '=': conditions.push(value + ' == ' + attribute.value.inspect()); break;
+ case '~=': conditions.push(splitValueBy(' ') + '.include(' + attribute.value.inspect() + ')'); break;
+ case '|=': conditions.push(
+ splitValueBy('-') + '.first().toUpperCase() == ' + attribute.value.toUpperCase().inspect()
+ ); break;
+ case '!=': conditions.push(value + ' != ' + attribute.value.inspect()); break;
+ case '':
+ case undefined: conditions.push('element.hasAttribute(' + attribute.name.inspect() + ')'); break;
+ default: throw 'Unknown operator ' + attribute.operator + ' in selector';
+ }
+ });
+ }
+
+ return conditions.join(' && ');
+ },
+
+ compileMatcher: function() {
+ this.match = new Function('element', 'if (!element.tagName) return false; \
+ element = $(element); \
+ return ' + this.buildMatchExpression());
+ },
+
+ findElements: function(scope) {
+ var element;
+
+ if (element = $(this.params.id))
+ if (this.match(element))
+ if (!scope || Element.childOf(element, scope))
+ return [element];
+
+ scope = (scope || document).getElementsByTagName(this.params.tagName || '*');
+
+ var results = [];
+ for (var i = 0, length = scope.length; i < length; i++)
+ if (this.match(element = scope[i]))
+ results.push(Element.extend(element));
+
+ return results;
+ },
+
+ toString: function() {
+ return this.expression;
+ }
+}
+
+Object.extend(Selector, {
+ matchElements: function(elements, expression) {
+ var selector = new Selector(expression);
+ return elements.select(selector.match.bind(selector)).map(Element.extend);
+ },
+
+ findElement: function(elements, expression, index) {
+ if (typeof expression == 'number') index = expression, expression = false;
+ return Selector.matchElements(elements, expression || '*')[index || 0];
+ },
+
+ findChildElements: function(element, expressions) {
+ return expressions.map(function(expression) {
+ return expression.match(/[^\s"]+(?:"[^"]*"[^\s"]+)*/g).inject([null], function(results, expr) {
+ var selector = new Selector(expr);
+ return results.inject([], function(elements, result) {
+ return elements.concat(selector.findElements(result || element));
+ });
+ });
+ }).flatten();
+ }
+});
+
+function $$() {
+ return Selector.findChildElements(document, $A(arguments));
+}
+var Form = {
+ reset: function(form) {
+ $(form).reset();
+ return form;
+ },
+
+ serializeElements: function(elements, getHash) {
+ var data = elements.inject({}, function(result, element) {
+ if (!element.disabled && element.name) {
+ var key = element.name, value = $(element).getValue();
+ if (value != undefined) {
+ if (result[key]) {
+ if (result[key].constructor != Array) result[key] = [result[key]];
+ result[key].push(value);
+ }
+ else result[key] = value;
+ }
+ }
+ return result;
+ });
+
+ return getHash ? data : Hash.toQueryString(data);
+ }
+};
+
+Form.Methods = {
+ serialize: function(form, getHash) {
+ return Form.serializeElements(Form.getElements(form), getHash);
+ },
+
+ 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().each(function(element) {
+ element.blur();
+ element.disabled = 'true';
+ });
+ return form;
+ },
+
+ enable: function(form) {
+ form = $(form);
+ form.getElements().each(function(element) {
+ element.disabled = '';
+ });
+ return form;
+ },
+
+ findFirstElement: function(form) {
+ return $(form).getElements().find(function(element) {
+ return element.type != 'hidden' && !element.disabled &&
+ ['input', 'select', 'textarea'].include(element.tagName.toLowerCase());
+ });
+ },
+
+ focusFirstElement: function(form) {
+ form = $(form);
+ form.findFirstElement().activate();
+ return form;
+ }
+}
+
+Object.extend(Form, Form.Methods);
+
+/*--------------------------------------------------------------------------*/
+
+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 Hash.toQueryString(pair);
+ }
+ }
+ return '';
+ },
+
+ getValue: function(element) {
+ element = $(element);
+ var method = element.tagName.toLowerCase();
+ return Form.Element.Serializers[method](element);
+ },
+
+ clear: function(element) {
+ $(element).value = '';
+ return element;
+ },
+
+ present: function(element) {
+ return $(element).value != '';
+ },
+
+ activate: function(element) {
+ element = $(element);
+ element.focus();
+ if (element.select && ( element.tagName.toLowerCase() != 'input' ||
+ !['button', 'reset', 'submit'].include(element.type) ) )
+ element.select();
+ return element;
+ },
+
+ disable: function(element) {
+ element = $(element);
+ element.disabled = true;
+ return element;
+ },
+
+ enable: function(element) {
+ element = $(element);
+ element.blur();
+ element.disabled = false;
+ return element;
+ }
+}
+
+Object.extend(Form.Element, Form.Element.Methods);
+var Field = Form.Element;
+var $F = Form.Element.getValue;
+
+/*--------------------------------------------------------------------------*/
+
+Form.Element.Serializers = {
+ input: function(element) {
+ switch (element.type.toLowerCase()) {
+ case 'checkbox':
+ case 'radio':
+ return Form.Element.Serializers.inputSelector(element);
+ default:
+ return Form.Element.Serializers.textarea(element);
+ }
+ },
+
+ inputSelector: function(element) {
+ return element.checked ? element.value : null;
+ },
+
+ textarea: function(element) {
+ return element.value;
+ },
+
+ select: function(element) {
+ return this[element.type == 'select-one' ?
+ 'selectOne' : 'selectMany'](element);
+ },
+
+ 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 = function() {}
+Abstract.TimedObserver.prototype = {
+ initialize: function(element, frequency, callback) {
+ this.frequency = frequency;
+ this.element = $(element);
+ this.callback = callback;
+
+ this.lastValue = this.getValue();
+ this.registerCallback();
+ },
+
+ registerCallback: function() {
+ setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
+ },
+
+ onTimerEvent: function() {
+ var value = this.getValue();
+ var changed = ('string' == typeof this.lastValue && 'string' == typeof value
+ ? this.lastValue != value : String(this.lastValue) != String(value));
+ if (changed) {
+ this.callback(this.element, value);
+ this.lastValue = value;
+ }
+ }
+}
+
+Form.Element.Observer = Class.create();
+Form.Element.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
+ getValue: function() {
+ return Form.Element.getValue(this.element);
+ }
+});
+
+Form.Observer = Class.create();
+Form.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
+ getValue: function() {
+ return Form.serialize(this.element);
+ }
+});
+
+/*--------------------------------------------------------------------------*/
+
+Abstract.EventObserver = function() {}
+Abstract.EventObserver.prototype = {
+ 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.bind(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();
+Form.Element.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
+ getValue: function() {
+ return Form.Element.getValue(this.element);
+ }
+});
+
+Form.EventObserver = Class.create();
+Form.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
+ getValue: function() {
+ return Form.serialize(this.element);
+ }
+});
+if (!window.Event) {
+ var Event = new Object();
+}
+
+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,
+
+ element: function(event) {
+ return event.target || event.srcElement;
+ },
+
+ isLeftClick: function(event) {
+ return (((event.which) && (event.which == 1)) ||
+ ((event.button) && (event.button == 1)));
+ },
+
+ pointerX: function(event) {
+ return event.pageX || (event.clientX +
+ (document.documentElement.scrollLeft || document.body.scrollLeft));
+ },
+
+ pointerY: function(event) {
+ return event.pageY || (event.clientY +
+ (document.documentElement.scrollTop || document.body.scrollTop));
+ },
+
+ stop: function(event) {
+ if (event.preventDefault) {
+ event.preventDefault();
+ event.stopPropagation();
+ } else {
+ event.returnValue = false;
+ event.cancelBubble = true;
+ }
+ },
+
+ // find the first node with the given tagName, starting from the
+ // node the event was triggered on; traverses the DOM upwards
+ findElement: function(event, tagName) {
+ var element = Event.element(event);
+ while (element.parentNode && (!element.tagName ||
+ (element.tagName.toUpperCase() != tagName.toUpperCase())))
+ element = element.parentNode;
+ return element;
+ },
+
+ observers: false,
+
+ _observeAndCache: function(element, name, observer, useCapture) {
+ if (!this.observers) this.observers = [];
+ if (element.addEventListener) {
+ this.observers.push([element, name, observer, useCapture]);
+ element.addEventListener(name, observer, useCapture);
+ } else if (element.attachEvent) {
+ this.observers.push([element, name, observer, useCapture]);
+ element.attachEvent('on' + name, observer);
+ }
+ },
+
+ unloadCache: function() {
+ if (!Event.observers) return;
+ for (var i = 0, length = Event.observers.length; i < length; i++) {
+ Event.stopObserving.apply(this, Event.observers[i]);
+ Event.observers[i][0] = null;
+ }
+ Event.observers = false;
+ },
+
+ observe: function(element, name, observer, useCapture) {
+ element = $(element);
+ useCapture = useCapture || false;
+
+ if (name == 'keypress' &&
+ (navigator.appVersion.match(/Konqueror|Safari|KHTML/)
+ || element.attachEvent))
+ name = 'keydown';
+
+ Event._observeAndCache(element, name, observer, useCapture);
+ },
+
+ stopObserving: function(element, name, observer, useCapture) {
+ element = $(element);
+ useCapture = useCapture || false;
+
+ if (name == 'keypress' &&
+ (navigator.appVersion.match(/Konqueror|Safari|KHTML/)
+ || element.detachEvent))
+ name = 'keydown';
+
+ if (element.removeEventListener) {
+ element.removeEventListener(name, observer, useCapture);
+ } else if (element.detachEvent) {
+ try {
+ element.detachEvent('on' + name, observer);
+ } catch (e) {}
+ }
+ }
+});
+
+/* prevent memory leaks in IE */
+if (navigator.appVersion.match(/\bMSIE\b/))
+ Event.observe(window, 'unload', Event.unloadCache, false);
+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;
+ },
+
+ realOffset: function(element) {
+ var valueT = 0, valueL = 0;
+ do {
+ valueT += element.scrollTop || 0;
+ valueL += element.scrollLeft || 0;
+ element = element.parentNode;
+ } while (element);
+ return [valueL, valueT];
+ },
+
+ cumulativeOffset: function(element) {
+ var valueT = 0, valueL = 0;
+ do {
+ valueT += element.offsetTop || 0;
+ valueL += element.offsetLeft || 0;
+ element = element.offsetParent;
+ } while (element);
+ return [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 == 'relative' || p == 'absolute') break;
+ }
+ } while (element);
+ return [valueL, valueT];
+ },
+
+ offsetParent: 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;
+ },
+
+ // 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 = this.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 = this.realOffset(element);
+
+ this.xcomp = x + offsetcache[0] - this.deltaX;
+ this.ycomp = y + offsetcache[1] - this.deltaY;
+ this.offset = this.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;
+ },
+
+ page: 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)
+ if (Element.getStyle(element,'position')=='absolute') break;
+
+ } while (element = element.offsetParent);
+
+ element = forElement;
+ do {
+ if (!window.opera || element.tagName=='BODY') {
+ valueT -= element.scrollTop || 0;
+ valueL -= element.scrollLeft || 0;
+ }
+ } while (element = element.parentNode);
+
+ return [valueL, valueT];
+ },
+
+ clone: function(source, target) {
+ 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 = Position.page(source);
+
+ // find coordinate system to use
+ target = $(target);
+ 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(target,'position') == 'absolute') {
+ parent = Position.offsetParent(target);
+ delta = Position.page(parent);
+ }
+
+ // 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) target.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px';
+ if(options.setTop) target.style.top = (p[1] - delta[1] + options.offsetTop) + 'px';
+ if(options.setWidth) target.style.width = source.offsetWidth + 'px';
+ if(options.setHeight) target.style.height = source.offsetHeight + 'px';
+ },
+
+ absolutize: function(element) {
+ element = $(element);
+ if (element.style.position == 'absolute') return;
+ Position.prepare();
+
+ var offsets = Position.positionedOffset(element);
+ 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';
+ },
+
+ relativize: function(element) {
+ element = $(element);
+ if (element.style.position == 'relative') return;
+ Position.prepare();
+
+ 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;
+ }
+}
+
+// Safari returns margins on body which is incorrect if the child is absolutely
+// positioned. For performance reasons, redefine Position.cumulativeOffset for
+// KHTML/WebKit only.
+if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) {
+ Position.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 [valueL, valueT];
+ }
+}
+
+Element.addMethods();
\ No newline at end of file
17 years, 8 months
JBoss Rich Faces SVN: r516 - trunk/sandbox/scrollable-grid/src/main/config/component.
by richfaces-svn-commits@lists.jboss.org
Author: abelevich
Date: 2007-04-24 11:26:09 -0400 (Tue, 24 Apr 2007)
New Revision: 516
Modified:
trunk/sandbox/scrollable-grid/src/main/config/component/scrollable-grid.xml
Log:
Modified: trunk/sandbox/scrollable-grid/src/main/config/component/scrollable-grid.xml
===================================================================
--- trunk/sandbox/scrollable-grid/src/main/config/component/scrollable-grid.xml 2007-04-24 15:25:54 UTC (rev 515)
+++ trunk/sandbox/scrollable-grid/src/main/config/component/scrollable-grid.xml 2007-04-24 15:26:09 UTC (rev 516)
@@ -8,6 +8,23 @@
org.richfaces.component.html.HtmlScrollableGrid
</classname>
<superclass>org.richfaces.component.UIScrollableGrid</superclass>
- <description>Scrollable Grid</description>
+ <description>
+ <![CDATA[ Scrollable Grid ]]>
+ </description>
+
+ <renderer generate="true" override="true">
+ <name>org.richfaces.ScrollableGridRenderer</name>
+ <template>org/richfaces/scrollable-grid.jspx</template>
+ </renderer>
+
+
+ <tag>
+ <name>scrollable-grid</name>
+ <classname>org.richfaces.taglib.ScrollableGridTag</classname>
+ <superclass>
+ org.ajax4jsf.framework.taglib.HtmlComponentTagBase
+ </superclass>
+ </tag>
+ &ui_component_attributes;
</component>
</components>
\ No newline at end of file
17 years, 8 months