Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

GTNPORTAL-2849 GateIn Redirect Admin UI

  • Loading branch information...
commit d0511357542e632f282146a27c1c755e7872e6dc 1 parent 01cd788
ammendonca authored nscavell committed
Showing with 24,487 additions and 0 deletions.
  1. +3 −0  packaging/jboss-as7/pkg/package.xml
  2. +7 −0 packaging/jboss-as7/pkg/pom.xml
  3. +6 −0 packaging/jboss-as7/pkg/src/main/resources/jboss/main/gatein/gatein.ear/META-INF/application.xml
  4. +7 −0 packaging/jetty/pkg/pom.xml
  5. +7 −0 packaging/tomcat/pkg/pom.xml
  6. +8 −0 pom.xml
  7. +155 −0 portlet/admin/redirect/pom.xml
  8. +618 −0 portlet/admin/redirect/src/main/java/org/gatein/ui/admin/redirect/beans/EditRedirectBean.java
  9. +98 −0 portlet/admin/redirect/src/main/java/org/gatein/ui/admin/redirect/beans/RedirectsBean.java
  10. +22 −0 portlet/admin/redirect/src/main/java/org/gatein/ui/admin/redirect/beans/SessionBean.java
  11. +53 −0 portlet/admin/redirect/src/main/java/org/gatein/ui/admin/redirect/beans/util/PropertiesConverter.java
  12. +2 −0  portlet/admin/redirect/src/main/resources/locale/admin_en.properties
  13. +14 −0 portlet/admin/redirect/src/main/webapp/WEB-INF/faces-config.xml
  14. +14 −0 portlet/admin/redirect/src/main/webapp/WEB-INF/gatein-resources.xml
  15. +48 −0 portlet/admin/redirect/src/main/webapp/WEB-INF/portlet.xml
  16. +52 −0 portlet/admin/redirect/src/main/webapp/WEB-INF/web.xml
  17. +267 −0 portlet/admin/redirect/src/main/webapp/admin/redirects/index.xhtml
  18. +44 −0 portlet/admin/redirect/src/main/webapp/admin/redirects/menu.xhtml
  19. +169 −0 portlet/admin/redirect/src/main/webapp/admin/redirects/modals/modal-condition.xhtml
  20. +30 −0 portlet/admin/redirect/src/main/webapp/admin/redirects/modals/modal-delete_site.xhtml
  21. +41 −0 portlet/admin/redirect/src/main/webapp/admin/redirects/modals/modal-import_site.xhtml
  22. +33 −0 portlet/admin/redirect/src/main/webapp/admin/redirects/modals/modal-select_node.xhtml
  23. +52 −0 portlet/admin/redirect/src/main/webapp/admin/redirects/modals/modals.xhtml
  24. +302 −0 portlet/admin/redirect/src/main/webapp/resources/css/admin-responsive.css
  25. +1,274 −0 portlet/admin/redirect/src/main/webapp/resources/css/admin.css
  26. +1,088 −0 portlet/admin/redirect/src/main/webapp/resources/css/bootstrap-responsive.css
  27. +5,893 −0 portlet/admin/redirect/src/main/webapp/resources/css/bootstrap.css
  28. +233 −0 portlet/admin/redirect/src/main/webapp/resources/font-awesome/css/font-awesome.css
  29. BIN  portlet/admin/redirect/src/main/webapp/resources/font-awesome/font/fontawesome-webfont.eot
  30. +175 −0 portlet/admin/redirect/src/main/webapp/resources/font-awesome/font/fontawesome-webfont.svg
  31. BIN  portlet/admin/redirect/src/main/webapp/resources/font-awesome/font/fontawesome-webfont.svgz
  32. BIN  portlet/admin/redirect/src/main/webapp/resources/font-awesome/font/fontawesome-webfont.ttf
  33. BIN  portlet/admin/redirect/src/main/webapp/resources/font-awesome/font/fontawesome-webfont.woff
  34. +264 −0 portlet/admin/redirect/src/main/webapp/resources/font-awesome/less/font-awesome.less
  35. +513 −0 portlet/admin/redirect/src/main/webapp/resources/font-awesome/sass/font-awesome.sass
  36. +267 −0 portlet/admin/redirect/src/main/webapp/resources/font-awesome/sass/font-awesome.scss
  37. BIN  portlet/admin/redirect/src/main/webapp/resources/img/actions-border-top.png
  38. BIN  portlet/admin/redirect/src/main/webapp/resources/img/body-bg.jpg
  39. BIN  portlet/admin/redirect/src/main/webapp/resources/img/bullet-separator.png
  40. BIN  portlet/admin/redirect/src/main/webapp/resources/img/divider-vertical.png
  41. BIN  portlet/admin/redirect/src/main/webapp/resources/img/favicon.ico
  42. BIN  portlet/admin/redirect/src/main/webapp/resources/img/gatein_logo_grey.png
  43. BIN  portlet/admin/redirect/src/main/webapp/resources/img/glyphicons-halflings-gray.png
  44. BIN  portlet/admin/redirect/src/main/webapp/resources/img/glyphicons-halflings-white.png
  45. BIN  portlet/admin/redirect/src/main/webapp/resources/img/glyphicons-halflings.png
  46. BIN  portlet/admin/redirect/src/main/webapp/resources/img/icon-arrow-closed.png
  47. BIN  portlet/admin/redirect/src/main/webapp/resources/img/icon-arrow-opened.png
  48. BIN  portlet/admin/redirect/src/main/webapp/resources/img/icon-close.png
  49. BIN  portlet/admin/redirect/src/main/webapp/resources/img/icon-grippy.png
  50. BIN  portlet/admin/redirect/src/main/webapp/resources/img/icon-ok.png
  51. BIN  portlet/admin/redirect/src/main/webapp/resources/img/icon-switch-on-off.png
  52. BIN  portlet/admin/redirect/src/main/webapp/resources/img/logo.png
  53. BIN  portlet/admin/redirect/src/main/webapp/resources/img/site-redirects.png
  54. +556 −0 portlet/admin/redirect/src/main/webapp/resources/js/admin.js
  55. +90 −0 portlet/admin/redirect/src/main/webapp/resources/js/bootstrap-alert.js
  56. +96 −0 portlet/admin/redirect/src/main/webapp/resources/js/bootstrap-button.js
  57. +100 −0 portlet/admin/redirect/src/main/webapp/resources/js/bootstrap-dropdown.js
  58. +218 −0 portlet/admin/redirect/src/main/webapp/resources/js/bootstrap-modal.js
  59. +275 −0 portlet/admin/redirect/src/main/webapp/resources/js/bootstrap-tooltip.js
  60. +1,824 −0 portlet/admin/redirect/src/main/webapp/resources/js/bootstrap.js
  61. +9,473 −0 portlet/admin/redirect/src/main/webapp/resources/js/jquery-1.8.3.js
  62. +41 −0 portlet/admin/redirect/src/main/webapp/template.xhtml
  63. +1 −0  portlet/pom.xml
  64. +32 −0 web/portal/src/main/webapp/WEB-INF/conf/portal/application-registry-configuration.xml
  65. +6 −0 web/portal/src/main/webapp/WEB-INF/conf/portal/group/platform/administrators/navigation.xml
  66. +16 −0 web/portal/src/main/webapp/WEB-INF/conf/portal/group/platform/administrators/pages.xml
View
3  packaging/jboss-as7/pkg/package.xml
@@ -130,6 +130,9 @@
<copy tofile="${jbossas.target.dir}/gatein/gatein.ear/exoadmin.war">
<fileset refid="org.gatein.portal:exo.portal.portlet.exoadmin:war"/>
</copy>
+ <copy tofile="${jbossas.target.dir}/gatein/gatein.ear/redirect-admin.war">
+ <fileset refid="org.gatein.portal.portlet:redirect-admin-ui:war"/>
+ </copy>
<copy tofile="${jbossas.target.dir}/gatein/gatein.ear/eXoGadgets.war">
<fileset refid="org.gatein.portal:exo.portal.eXoGadgets:war"/>
</copy>
View
7 packaging/jboss-as7/pkg/pom.xml
@@ -193,6 +193,13 @@
<type>war</type>
</dependency>
+ <!-- Site Redirection Admin Portlet -->
+ <dependency>
+ <groupId>org.gatein.portal.portlet</groupId>
+ <artifactId>redirect-admin-ui</artifactId>
+ <type>war</type>
+ </dependency>
+
<!-- Need to declare this artifact to have access to its path from package.xml -->
<dependency>
<groupId>org.gatein.portal</groupId>
View
6 packaging/jboss-as7/pkg/src/main/resources/jboss/main/gatein/gatein.ear/META-INF/application.xml
@@ -23,6 +23,12 @@
</module>
<module>
<web>
+ <web-uri>redirect-admin.war</web-uri>
+ <context-root>redirect-admin</context-root>
+ </web>
+ </module>
+ <module>
+ <web>
<web-uri>exoadmin.war</web-uri>
<context-root>exoadmin</context-root>
</web>
View
7 packaging/jetty/pkg/pom.xml
@@ -901,6 +901,13 @@
<type>war</type>
</dependency>
+ <dependency>
+ <?rename redirect-admin.war?>
+ <groupId>org.gatein.portal.portlet</groupId>
+ <artifactId>redirect-admin-ui</artifactId>
+ <type>war</type>
+ </dependency>
+
</dependencies>
<build>
View
7 packaging/tomcat/pkg/pom.xml
@@ -894,6 +894,13 @@
</dependency>
<dependency>
+ <?rename redirect-admin.war?>
+ <groupId>org.gatein.portal.portlet</groupId>
+ <artifactId>redirect-admin-ui</artifactId>
+ <type>war</type>
+ </dependency>
+
+ <dependency>
<?rename gatein-mobile-configuration.war?>
<groupId>org.gatein.portal</groupId>
<artifactId>mobile-extension-configuration</artifactId>
View
8 pom.xml
@@ -737,6 +737,14 @@
<type>war</type>
</dependency>
+ <!-- GateIn Redirect Admin -->
+ <dependency>
+ <groupId>org.gatein.portal.portlet</groupId>
+ <artifactId>redirect-admin-ui</artifactId>
+ <version>${project.version}</version>
+ <type>war</type>
+ </dependency>
+
<!-- GateIn Mobile -->
<dependency>
<groupId>org.gatein.portal</groupId>
View
155 portlet/admin/redirect/pom.xml
@@ -0,0 +1,155 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.gatein.portal</groupId>
+ <artifactId>exo.portal.portlet</artifactId>
+ <version>3.6.0.MO1-SNAPSHOT</version>
+ <relativePath>../..</relativePath>
+ </parent>
+
+ <groupId>org.gatein.portal.portlet</groupId>
+ <artifactId>redirect-admin-ui</artifactId>
+
+ <packaging>war</packaging>
+
+ <name>GateIn Redirect Admin UI Portlet</name>
+
+ <properties>
+ <version.richfaces>4.3.0-SNAPSHOT</version.richfaces>
+ <qualifier.richfaces>jbas71</qualifier.richfaces>
+ <version.richfaces.bootstrap>4.3.0-SNAPSHOT</version.richfaces.bootstrap>
+
+ <!-- JSF2 Implementations -->
+ <version.mojarra2>2.1.13</version.mojarra2>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.gatein.api</groupId>
+ <artifactId>gatein-api</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.gatein.common</groupId>
+ <artifactId>common-common</artifactId>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.exoplatform.kernel</groupId>
+ <artifactId>exo.kernel.container</artifactId>
+ <version>${org.exoplatform.kernel.version}</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.gatein.portal</groupId>
+ <artifactId>exo.portal.component.portal</artifactId>
+ <scope>provided</scope>
+ <exclusions>
+ <exclusion>
+ <groupId>org.chromattic</groupId>
+ <artifactId>chromattic.api</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.chromattic</groupId>
+ <artifactId>chromattic.apt</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.chromattic</groupId>
+ <artifactId>chromattic.common</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.chromattic</groupId>
+ <artifactId>chromattic.metamodel</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.chromattic</groupId>
+ <artifactId>chromattic.spi</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+
+ <dependency>
+ <groupId>com.sun.faces</groupId>
+ <artifactId>jsf-api</artifactId>
+ <version>${version.mojarra2}</version>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.jboss.portletbridge</groupId>
+ <artifactId>richfaces4-depchain</artifactId>
+ <type>pom</type>
+ <version>${org.jboss.portletbridge.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.richfaces.ui</groupId>
+ <artifactId>richfaces-components-ui</artifactId>
+ <version>${version.richfaces}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.richfaces.core</groupId>
+ <artifactId>richfaces-core-impl</artifactId>
+ <version>${version.richfaces}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.richfaces.sandbox.ui.bootstrap</groupId>
+ <artifactId>bootstrap-ui</artifactId>
+ <version>${version.richfaces.bootstrap}</version>
+ </dependency>
+ </dependencies>
+
+ <profiles>
+ <!-- For tomcat we need to bundle the JSF libs in WEB-INF/lib -->
+ <profile>
+ <id>tomcat7</id>
+ <activation>
+ <property>
+ <name>gatein.dev</name>
+ <value>tomcat7</value>
+ </property>
+ </activation>
+ <dependencies>
+ <dependency>
+ <groupId>com.sun.faces</groupId>
+ <artifactId>jsf-api</artifactId>
+ <version>${version.mojarra2}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.sun.faces</groupId>
+ <artifactId>jsf-impl</artifactId>
+ <version>${version.mojarra2}</version>
+ </dependency>
+ </dependencies>
+ </profile>
+ <profile>
+ <id>tomcat</id>
+ <activation>
+ <property>
+ <name>gatein.dev</name>
+ <value>tomcat</value>
+ </property>
+ </activation>
+ <dependencies>
+ <dependency>
+ <groupId>com.sun.faces</groupId>
+ <artifactId>jsf-api</artifactId>
+ <version>${version.mojarra2}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.sun.faces</groupId>
+ <artifactId>jsf-impl</artifactId>
+ <version>${version.mojarra2}</version>
+ </dependency>
+ </dependencies>
+ </profile>
+ </profiles>
+
+ <build>
+ <finalName>redirect-admin</finalName>
+ </build>
+</project>
View
618 portlet/admin/redirect/src/main/java/org/gatein/ui/admin/redirect/beans/EditRedirectBean.java
@@ -0,0 +1,618 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2012, Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+
+package org.gatein.ui.admin.redirect.beans;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+import javax.faces.bean.ManagedBean;
+import javax.faces.bean.ViewScoped;
+import javax.faces.context.FacesContext;
+
+import org.exoplatform.container.ExoContainerContext;
+import org.exoplatform.portal.config.DataStorage;
+import org.exoplatform.portal.config.model.DevicePropertyCondition;
+import org.exoplatform.portal.config.model.NodeMap;
+import org.exoplatform.portal.config.model.PortalConfig;
+import org.exoplatform.portal.config.model.PortalRedirect;
+import org.exoplatform.portal.config.model.RedirectCondition;
+import org.exoplatform.portal.config.model.RedirectMappings;
+import org.exoplatform.portal.config.model.UserAgentConditions;
+import org.gatein.api.PortalRequest;
+import org.gatein.api.navigation.Node;
+import org.gatein.api.navigation.Nodes;
+import org.gatein.api.site.SiteId;
+
+@ManagedBean(name = "rdrEdit")
+@ViewScoped
+public class EditRedirectBean implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ private boolean isEdit = false;
+
+ public boolean getIsEdit() {
+ return isEdit;
+ }
+
+ public void setIsEdit(boolean isEdit) {
+ this.isEdit = isEdit;
+ }
+
+ DataStorage ds = null;
+ PortalConfig cfg = null;
+
+ protected PortalRedirect pr;
+
+ // So we keep a reference to redirects with updated name
+ protected String originalName;
+
+ protected String redirectName;
+ protected boolean enabled;
+ protected String redirectSite;
+
+ protected RedirectMappings mappings;
+
+ private boolean isNewRedirect;
+
+ /**
+ * Sets the name of the Redirect to be edited. It's _NOT_ used to change the current redirect name!
+ */
+ public void configRedirect() {
+ Map<String, String> params = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap();
+ redirectName = params.get("rname");
+ }
+
+ public void addRedirect(String site) {
+ this.siteName = site;
+ this.pr = new PortalRedirect();
+ this.pr.setConditions(new ArrayList<RedirectCondition>());
+ RedirectMappings rm = new RedirectMappings();
+ rm.setMappings(new ArrayList<NodeMap>());
+ this.pr.setMappings(rm);
+ this.mappings = pr.getMappings();
+ isNewRedirect = true;
+ }
+
+ /**
+ * Returns the name of the redirect being edited.
+ *
+ * @return
+ */
+ public String getName() {
+ return this.pr != null ? this.pr.getName() : redirectName;
+ }
+
+ /**
+ * Sets the Redirect Name.
+ *
+ * @param name
+ */
+ public void setName(String name) {
+ if (this.pr != null) {
+ this.pr.setName(name);
+ }
+ this.redirectName = name;
+ }
+
+ /**
+ * Toggles redirect enabled/disabled state. Persisted immediately, as it's used for the redirects listing.
+ *
+ * @param site the site the affected redirect belongs to
+ * @param name the name of the redirect to be enabled/disabled
+ */
+ public void toggleEnabled(String site, String name) {
+ try {
+ // FIXME: Use webui Util.getUIPortal();
+ if (ds == null) {
+ ds = (DataStorage) ExoContainerContext.getCurrentContainer().getComponentInstanceOfType(DataStorage.class);
+ }
+
+ cfg = ds.getPortalConfig(site);
+ for (PortalRedirect pr : cfg.getPortalRedirects()) {
+ if (pr.getName().equals(name)) {
+ pr.setEnabled(!pr.isEnabled());
+ ds.save(cfg);
+ return;
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void toggleEnabled() {
+ toggleEnabled(siteName, redirectName);
+ }
+
+ public String deleteRedirect(String site, String name) {
+ try {
+ // FIXME: Use webui Util.getUIPortal();
+ if (ds == null) {
+ ds = (DataStorage) ExoContainerContext.getCurrentContainer().getComponentInstanceOfType(DataStorage.class);
+ }
+
+ cfg = ds.getPortalConfig(site);
+ ArrayList<PortalRedirect> redirects = cfg.getPortalRedirects();
+
+ int index = -1;
+ for (int i = 0; i < redirects.size(); i++) {
+ if (redirects.get(i).getName().equals(name)) {
+ index = i;
+ break;
+ }
+ }
+
+ if (index != -1) {
+ redirects.remove(index);
+ cfg.setPortalRedirects(redirects);
+ ds.save(cfg);
+ } else {
+ // redirect was not found or deleted...
+ }
+ } catch (Exception e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ /**
+ * After editing a redirect, save/persist it.
+ *
+ * @return
+ */
+ public String saveRedirect() {
+ try {
+ // FIXME: Use webui Util.getUIPortal();
+ if (ds == null) {
+ ds = (DataStorage) ExoContainerContext.getCurrentContainer().getComponentInstanceOfType(DataStorage.class);
+ }
+
+ cfg = ds.getPortalConfig(siteName);
+ ArrayList<PortalRedirect> redirects = cfg.getPortalRedirects();
+ // FIXME: getPortalRedirects() should return empty list instead of null
+ if (redirects == null) {
+ redirects = new ArrayList<PortalRedirect>();
+ }
+ boolean save = false;
+ if (isNewRedirect) {
+ redirects.add(pr);
+ save = true;
+ } else {
+ int index = -1;
+ for (int i = 0; i < redirects.size(); i++) {
+ if (redirects.get(i).getName().equals(originalName)) {
+ index = i;
+ break;
+ }
+ }
+ if (index != -1) {
+ redirects.set(index, this.pr);
+ save = true;
+ }
+ }
+
+ if (save) {
+ cfg.setPortalRedirects(redirects);
+ ds.save(cfg);
+ isNewRedirect = false;
+ } else {
+ // redirect was not found or saved...
+ }
+ } catch (Exception e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ /**
+ * After editing a redirect, cancel it's changes. Method restores the redirect state, name, conditions, mappings, etc to
+ * it's backup state. TODO: Try to clone the entire redirect for backup.
+ */
+ public void rollbackRedirect() {
+ isEdit = false;
+ }
+
+ // ----- REDIRECT ENABLED, NAME & SITE -----
+
+ /**
+ * Sets the enabled/disabled state of a redirect, in edit mode. As it is in edit mode, it is not persisted as in {
+ * {@link #toggleEnabled(String, String)}, since it can be canceled.
+ *
+ * @param enabled the value to set the enabled property
+ */
+ public void setEnabled(boolean enabled) {
+ pr.setEnabled(enabled);
+ }
+
+ /**
+ * Getter for the redirect enabled property, indicating if the redirect is active or not.
+ *
+ * @return a boolean indicating the redirect enabled property
+ */
+ public boolean getEnabled() {
+ return pr != null ? pr.isEnabled() : false;
+ }
+
+ public String getRedirectSite() {
+ return this.pr != null ? this.pr.getRedirectSite() : null;
+ }
+
+ public void setRedirectSite(String redirectSite) {
+ this.pr.setRedirectSite(redirectSite);
+ }
+
+ // ----- CONDITIONS -----
+
+ public ArrayList<RedirectCondition> getConditions() {
+ return pr != null ? pr.getConditions() : new ArrayList<RedirectCondition>();
+ }
+
+ public void setConditions(ArrayList<RedirectCondition> conditions) {
+ pr.setConditions(conditions);
+ }
+
+ // current condition being edited
+ private int currentConditionIndex;
+ private RedirectCondition editedCondition;
+
+ private ArrayList<String> backupContains;
+ private ArrayList<String> backupDoesNotContain;
+ private ArrayList<DevicePropertyCondition> backupDeviceProperties;
+
+ private boolean conditionsChanged = false;
+ private boolean isNewCondition = false;
+
+ private String siteName;
+
+ // holds selected node mapping site option
+ private String nodesSiteName;
+ // holds origin node names
+ private List<String> originNodeNames = new ArrayList<String>();
+ // holds redirect node names
+ private List<String> redirectNodeNames = new ArrayList<String>();
+ // copy of either origin or redirect node names, depending on selection
+ private List<String> currentNodeNames = new ArrayList<String>();
+
+ public int getCurrentConditionIndex() {
+ return currentConditionIndex;
+ }
+
+ public void setCurrentConditionIndex(int currentConditionIndex) {
+ this.currentConditionIndex = currentConditionIndex;
+ }
+
+ public RedirectCondition getEditedCondition() {
+ return editedCondition;
+ }
+
+ public void setEditedCondition(RedirectCondition editedCondition) {
+ this.editedCondition = editedCondition;
+ this.backupContains = new ArrayList<String>(editedCondition.getUserAgentConditions().getContains());
+ this.backupDoesNotContain = new ArrayList<String>(editedCondition.getUserAgentConditions().getDoesNotContain());
+ this.backupDeviceProperties = editedCondition.getDeviceProperties() == null ? new ArrayList<DevicePropertyCondition>()
+ : new ArrayList<DevicePropertyCondition>(editedCondition.getDeviceProperties());
+ this.conditionsChanged = false;
+ }
+
+ public ArrayList<String> getContains(String condition) {
+ return editedCondition.getUserAgentConditions().getContains();
+ }
+
+ public void addCondition() {
+ this.editedCondition = createNewCondition();
+ isNewCondition = true;
+ }
+
+ /**
+ * Removes a Redirect Condition entry from the edited redirect.
+ *
+ * @param index the index of the entry to remove
+ */
+ public void removeCondition(Integer index) {
+ RedirectCondition rc = pr.getConditions().remove((int) index);
+ }
+
+ /**
+ * Creates a new redirect condition, sanitizing the initial values, as they are set to null instead of empty ArrayLists,
+ * etc.
+ *
+ * @return
+ */
+ private RedirectCondition createNewCondition() {
+ RedirectCondition newRC = new RedirectCondition();
+ newRC.setName("");
+ newRC.setDeviceProperties(new ArrayList<DevicePropertyCondition>());
+ UserAgentConditions newUAC = new UserAgentConditions();
+ newUAC.setContains(new ArrayList<String>());
+ newUAC.setDoesNotContain(new ArrayList<String>());
+ newRC.setUserAgentConditions(newUAC);
+
+ return newRC;
+ }
+
+ /**
+ * Adds a new "CONTAINS" entry to the edited condition.
+ */
+ public void addContains() {
+ editedCondition.getUserAgentConditions().getContains().add("");
+ conditionsChanged = true;
+ }
+
+ /**
+ * Removes a "CONTAINS" entry from the edited condition.
+ *
+ * @param index the index of the entry to remove
+ */
+ public void removeContains(Integer index) {
+ String rc = editedCondition.getUserAgentConditions().getContains().remove((int) index);
+ conditionsChanged = true;
+ }
+
+ /**
+ * Adds a new "DOES NOT CONTAIN" entry to the edited condition.
+ */
+ public void addDoesNotContain() {
+ editedCondition.getUserAgentConditions().getDoesNotContain().add("");
+ conditionsChanged = true;
+ }
+
+ /**
+ * Removes a "DOES NOT CONTAIN" entry from the edited condition.
+ *
+ * @param index the index of the entry to remove
+ */
+ public void removeDoesNotContain(Integer index) {
+ String rc = editedCondition.getUserAgentConditions().getDoesNotContain().remove((int) index);
+ conditionsChanged = true;
+ }
+
+ public boolean getConditionsChanged() {
+ return conditionsChanged;
+ }
+
+ /**
+ * After editing a condition, save it. Method does nothing, as all changes should be already present in the object.
+ *
+ * @return
+ */
+ public String saveCondition() {
+ if (isNewCondition) {
+ this.pr.getConditions().add(editedCondition);
+ isNewCondition = false;
+ conditionsChanged = false;
+ }
+ return null;
+ }
+
+ /**
+ * After editing a condition, cancel it's changes. Method restores the conditions, properties, etc to it's backup state.
+ * TODO: Try to clone the entire condition for backup.
+ */
+ public void rollbackCondition() {
+ if (!isNewCondition) {
+ this.editedCondition.getUserAgentConditions().setContains(backupContains);
+ this.editedCondition.getUserAgentConditions().setDoesNotContain(backupDoesNotContain);
+ this.editedCondition.setDeviceProperties(backupDeviceProperties);
+ }
+ }
+
+ // ----- PROPERTIES -----
+
+ /**
+ * Adds a new Device Property to the edited condition.
+ */
+ public void addProperty() {
+ if (editedCondition.getDeviceProperties() == null) {
+ editedCondition.setDeviceProperties(new ArrayList<DevicePropertyCondition>());
+ }
+
+ editedCondition.getDeviceProperties().add(new DevicePropertyCondition());
+ }
+
+ /**
+ * Removes a Device Property entry from the edited condition.
+ *
+ * @param index the index of the entry to remove
+ */
+ public void removeProperty(Integer index) {
+ DevicePropertyCondition rc = editedCondition.getDeviceProperties().remove((int) index);
+ conditionsChanged = true;
+ }
+
+ /**
+ * Gets the proper operator to be shown at property editor, mapping it to the &lt;select&gt; element.
+ *
+ * @param index the index of the entry to get the operator from
+ * @return a string value representing the operator (mt for matches, bt for between, gt for greater-than, lt for less-than
+ * and eq for equals)
+ */
+ public String getPropertyOperator(int index) {
+ DevicePropertyCondition dp = editedCondition.getDeviceProperties().get(index);
+ if (dp.getMatches() != null && !dp.getMatches().trim().isEmpty()) {
+ return "mt";
+ } else if (dp.getGreaterThan() != null && dp.getLessThan() != null && dp.getGreaterThan() != 0.0
+ && dp.getLessThan() != 0.0) {
+ return "bt";
+ } else if (dp.getGreaterThan() != null || dp.getGreaterThan() != 0.0) {
+ return "gt";
+ } else if (dp.getLessThan() != null || dp.getLessThan() != 0.0) {
+ return "lt";
+ } else {
+ return "eq";
+ }
+ }
+
+ // ----- MAPPINGS -----
+
+ public void addNodeMapping() {
+ this.pr.getMappings().getMappings().add(0, new NodeMap());
+ }
+
+ public void removeNodeMapping(int index) {
+ ArrayList<NodeMap> mappings = this.pr.getMappings().getMappings();
+ mappings.remove(index);
+ this.pr.getMappings().setMappings(mappings);
+ }
+
+ public boolean getUseNodeNameMatching() {
+ return (this.pr != null && this.pr.getMappings() != null) ? this.pr.getMappings().isUseNodeNameMatching() : false;
+ }
+
+ public void setUseNodeNameMatching(boolean useNodeNameMatching) {
+ this.pr.getMappings().setUseNodeNameMatching(useNodeNameMatching);
+ }
+
+ public RedirectMappings getMappings() {
+ return mappings;
+ }
+
+ public void setMappings(RedirectMappings mappings) {
+ this.mappings = mappings;
+ }
+
+ /**
+ * Returns the list of Portal nodes for the origin.
+ *
+ * @return a List of Strings representing node paths
+ */
+ public List<String> getOriginNodeNames() {
+ return this.originNodeNames;
+ }
+
+ /**
+ * Returns the list of Portal nodes for the redirect.
+ *
+ * @return a List of Strings representing node paths
+ */
+ public List<String> getRedirectNodeNames() {
+ return this.redirectNodeNames;
+ }
+
+ /**
+ * Returns the name of the Portal site for the selected option (origin or redirect) by {@link #setCurrentNodeNames(boolean)}
+ * .
+ *
+ * @return
+ */
+ public String getCurrentNodesSiteName() {
+ return nodesSiteName;
+ }
+
+ /**
+ * Returns the list of Portal nodes for the selected option (origin or redirect) by {@link #setCurrentNodeNames(boolean)}.
+ *
+ * @return
+ */
+ public List<String> getCurrentNodeNames() {
+ return currentNodeNames;
+ }
+
+ public void setCurrentNodeNames(boolean isOrigin) {
+ if (isOrigin) {
+ this.currentNodeNames = originNodeNames;
+ this.nodesSiteName = siteName;
+ } else {
+ this.currentNodeNames = redirectNodeNames;
+ this.nodesSiteName = redirectSite;
+ }
+ }
+
+ // --- Utilities ----------------------------------------------------------
+
+ public void load(String site, String redirect) {
+ isNewRedirect = false;
+
+ this.siteName = site;
+
+ // FIXME: Use webui Util.getUIPortal();
+ if (ds == null) {
+ ds = (DataStorage) ExoContainerContext.getCurrentContainer().getComponentInstanceOfType(DataStorage.class);
+ }
+
+ try {
+ cfg = ds.getPortalConfig(site);
+ for (PortalRedirect pr : cfg.getPortalRedirects()) {
+ if (pr.getName().equals(redirect)) {
+ this.pr = pr;
+ this.redirectName = pr.getName();
+ this.originalName = pr.getName();
+ this.enabled = pr.isEnabled();
+ this.redirectSite = pr.getRedirectSite();
+ this.mappings = pr.getMappings();
+ this.originNodeNames = loadOriginNodes(site);
+ this.redirectNodeNames = loadRedirectNodes();
+ isEdit = true;
+ return;
+ }
+ }
+ } catch (Exception e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
+ // TODO: move this to a different bean
+ public List<String> loadOriginNodes(String siteName) {
+ try {
+ ArrayList<String> nodes = new ArrayList<String>();
+ if (siteName != null) {
+ Node n = PortalRequest.getInstance().getPortal().getNavigation(new SiteId(siteName))
+ .getRootNode(Nodes.visitAll());
+ for (Node node : Nodes.asList(n)) {
+ nodes.add(node.getNodePath().toString());
+ }
+ }
+
+ return nodes;
+ } catch (Exception e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ public List<String> loadRedirectNodes() {
+ try {
+ ArrayList<String> nodes = new ArrayList<String>();
+ if (redirectSite != null) {
+ Node n = PortalRequest.getInstance().getPortal().getNavigation(new SiteId(redirectSite))
+ .getRootNode(Nodes.visitAll());
+ for (Node node : Nodes.asList(n)) {
+ nodes.add(node.getNodePath().toString());
+ }
+ }
+
+ this.redirectNodeNames = nodes;
+ return nodes;
+ } catch (Exception e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+}
View
98 portlet/admin/redirect/src/main/java/org/gatein/ui/admin/redirect/beans/RedirectsBean.java
@@ -0,0 +1,98 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2012, Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+
+package org.gatein.ui.admin.redirect.beans;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.faces.bean.ManagedBean;
+import javax.faces.bean.ViewScoped;
+
+import org.exoplatform.container.ExoContainerContext;
+import org.exoplatform.portal.config.DataStorage;
+import org.exoplatform.portal.config.model.PortalConfig;
+import org.exoplatform.portal.config.model.PortalRedirect;
+import org.gatein.api.PortalRequest;
+import org.gatein.api.site.Site;
+import org.gatein.api.site.SiteQuery;
+import org.gatein.api.site.SiteType;
+
+@ManagedBean(name = "rdrs")
+@ViewScoped
+public class RedirectsBean implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Fetches the full list of sites using GateIn API.
+ *
+ * @return
+ */
+ public List<Site> getSites() {
+ SiteQuery sq = new SiteQuery.Builder().withSiteTypes(SiteType.SITE).build();
+ List<Site> s = PortalRequest.getInstance().getPortal().findSites(sq);
+ return s;
+ }
+
+ // the selected site on the menu. we will show redirects for it
+ private String siteName = null;
+
+ public String getSiteName() {
+ return siteName;
+ }
+
+ public void setSiteName(String siteName) {
+ this.siteName = siteName;
+ }
+
+ /**
+ * Returns the list of redirects for the selected site.
+ *
+ * @return a List of {@link PortalRedirect} objects.
+ */
+ public List<PortalRedirect> getRedirects() {
+ if (siteName == null)
+ return new ArrayList<PortalRedirect>();
+
+ // FIXME: Use webui Util.getUIPortal();
+ DataStorage ds = (DataStorage) ExoContainerContext.getCurrentContainer().getComponentInstanceOfType(DataStorage.class);
+
+ ArrayList<PortalRedirect> r = new ArrayList<PortalRedirect>();
+ try {
+ PortalConfig cfg = ds.getPortalConfig(siteName);
+ r = cfg.getPortalRedirects();
+
+ // FIXME: getPortalRedirects() should return empty list
+ if (r == null) {
+ r = new ArrayList<PortalRedirect>();
+ }
+ } catch (Exception e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+
+ return r;
+ }
+
+}
View
22 portlet/admin/redirect/src/main/java/org/gatein/ui/admin/redirect/beans/SessionBean.java
@@ -0,0 +1,22 @@
+package org.gatein.ui.admin.redirect.beans;
+
+import java.io.Serializable;
+
+import javax.faces.bean.ManagedBean;
+import javax.faces.bean.SessionScoped;
+
+@ManagedBean(name = "sessionBean")
+@SessionScoped
+public class SessionBean implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ private boolean fluid = true;
+
+ public boolean isFluid() {
+ return fluid;
+ }
+
+ public void setFluid(boolean fluid) {
+ this.fluid = fluid;
+ }
+}
View
53 portlet/admin/redirect/src/main/java/org/gatein/ui/admin/redirect/beans/util/PropertiesConverter.java
@@ -0,0 +1,53 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2013, Red Hat, Inc. and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+
+package org.gatein.ui.admin.redirect.beans.util;
+
+import java.io.Serializable;
+
+import javax.faces.component.UIComponent;
+import javax.faces.context.FacesContext;
+import javax.faces.convert.Converter;
+import javax.faces.convert.FacesConverter;
+
+/**
+ * @author <a href="http://community.jboss.org/people/alexandrem">Alexandre Mendonça</a>
+ */
+@FacesConverter(forClass = java.lang.String.class, value = "PropertiesConverter")
+public class PropertiesConverter implements Converter, Serializable {
+
+ private static final long serialVersionUID = -6792916217369469319L;
+
+ public Object getAsObject(FacesContext context, UIComponent component, String value) {
+ if (value == null || value.trim().isEmpty()) {
+ return null;
+ }
+ return value;
+ }
+
+ public String getAsString(FacesContext context, UIComponent component, Object object) {
+ if (object == null)
+ return null;
+
+ return object.toString();
+ }
+}
View
2  portlet/admin/redirect/src/main/resources/locale/admin_en.properties
@@ -0,0 +1,2 @@
+portal.admin.adminPage=Admin Page Portal
+javax.portlet.title=Redirects Admin Portlet
View
14 portlet/admin/redirect/src/main/webapp/WEB-INF/faces-config.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<faces-config
+ xmlns="http://java.sun.com/xml/ns/javaee"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd"
+ version="2.0">
+
+ <context-param>
+ <param-name>javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL</param-name>
+ <param-value>true</param-value>
+ </context-param>
+
+</faces-config>
View
14 portlet/admin/redirect/src/main/webapp/WEB-INF/gatein-resources.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<gatein-resources
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.gatein.org/xml/ns/gatein_resources_1_3 http://www.gatein.org/xml/ns/gatein_resources_1_3"
+ xmlns="http://www.gatein.org/xml/ns/gatein_resources_1_3">
+
+ <portlet-skin>
+ <application-name>redirect-admin-portlet</application-name>
+ <portlet-name>RedirectsAdminPortlet</portlet-name>
+ <skin-name>Default</skin-name>
+ <css-path>/css/DefaultStylesheet.css</css-path>
+ </portlet-skin>
+
+</gatein-resources>
View
48 portlet/admin/redirect/src/main/webapp/WEB-INF/portlet.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<portlet-app xmlns="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd" version="2.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd
+ http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd">
+
+ <portlet>
+ <description xml:lang="EN">Site Redirects Portlet</description>
+ <portlet-name>RedirectsAdminPortlet</portlet-name>
+ <display-name xml:lang="EN">Site Redirects</display-name>
+
+ <portlet-class>javax.portlet.faces.GenericFacesPortlet</portlet-class>
+
+ <init-param>
+ <name>javax.portlet.faces.defaultViewId.view</name>
+ <value>/admin/redirects/index.xhtml</value>
+ </init-param>
+
+ <init-param>
+ <name>javax.portlet.faces.preserveActionParams</name>
+ <value>true</value>
+ </init-param>
+
+ <expiration-cache>0</expiration-cache>
+ <supports>
+ <mime-type>text/html</mime-type>
+ <portlet-mode>VIEW</portlet-mode>
+ </supports>
+
+ <portlet-info>
+ <title>GateIn Site Redirects Admin Portlet</title>
+ <short-title>Site Redirects Admin Portlet</short-title>
+ <keywords>Administration</keywords>
+ </portlet-info>
+
+ <security-role-ref>
+ <role-name>admin</role-name>
+ <role-link>admin</role-link>
+ </security-role-ref>
+
+ <container-runtime-option>
+ <name>org.gatein.pc.remotable</name>
+ <value>true</value>
+ </container-runtime-option>
+ </portlet>
+
+</portlet-app>
View
52 portlet/admin/redirect/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="richfaces-showcase" version="3.0">
+ <display-name>Redirects Admin Portlet</display-name>
+ <context-param>
+ <param-name>javax.portlet.faces.RENDER_POLICY</param-name>
+ <param-value>ALWAYS_DELEGATE</param-value>
+ </context-param>
+ <context-param>
+ <param-name>javax.faces.FACELETS_LIBRARIES</param-name>
+ <param-value>/WEB-INF/app-tags.taglib.xml</param-value>
+ </context-param>
+ <context-param>
+ <param-name>javax.faces.PROJECT_STAGE</param-name>
+ <param-value>Development</param-value>
+ </context-param>
+ <context-param>
+ <param-name>org.gatein.portletbridge.WAR_BUNDLES_PORTLETBRIDGE</param-name>
+ <param-value>true</param-value>
+ </context-param>
+ <context-param>
+ <param-name>javax.faces.FACELETS_SKIP_COMMENTS</param-name>
+ <param-value>true</param-value>
+ </context-param>
+ <context-param>
+ <param-name>org.richfaces.resourceOptimization.enabled</param-name>
+ <param-value>true</param-value>
+ </context-param>
+ <context-param>
+ <param-name>javax.faces.STATE_SAVING_METHOD</param-name>
+ <param-value>server</param-value>
+ </context-param>
+ <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>*.jsf</url-pattern>
+ </servlet-mapping>
+ <servlet-mapping>
+ <servlet-name>Faces Servlet</servlet-name>
+ <url-pattern>/faces/*</url-pattern>
+ </servlet-mapping>
+ <mime-mapping>
+ <extension>xcss</extension>
+ <mime-type>text/css</mime-type>
+ </mime-mapping>
+ <login-config>
+ <auth-method>BASIC</auth-method>
+ </login-config>
+</web-app>
View
267 portlet/admin/redirect/src/main/webapp/admin/redirects/index.xhtml
@@ -0,0 +1,267 @@
+<ui:composition template="/template.xhtml"
+ xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:rich="http://richfaces.org/rich"
+ xmlns:a4j="http://richfaces.org/a4j"
+ xmlns:b="http://richfaces.org/sandbox/bootstrap">
+
+<ui:define name="content">
+ <h:form id="add_form" styleClass="form-horizontal">
+ <h1 class="hOne"><a4j:outputPanel id="siteName"><h:outputText styleClass="gray" value="#{rdrs.siteName}" rendered="#{not empty rdrs.siteName}" /></a4j:outputPanel> Site Redirection</h1>
+ <a4j:commandLink action="#{rdrEdit.addRedirect(rdrs.siteName)}" styleClass="btn btn-small pull-right add-redirect" render=":edit_form" rendered="#{not empty rdrs.siteName}">Add Redirect</a4j:commandLink>
+ </h:form>
+ <h:form id="sum_form" styleClass="form-horizontal">
+ <!-- No site selected -->
+ <h:panelGroup rendered="#{empty rdrs.siteName}">
+ <h2 class="initial">Select a site to set up redirects.</h2>
+ <p class="initial">Redirect to an alternative site based on the device, browser or user preferences.</p>
+ <h:graphicImage class="initial" library="img" name="site-redirects.png" alt="Illustration: Arrow pointing from a laptop to a tablet and a smartphone" />
+ </h:panelGroup>
+
+ <!-- Site selected, with no redirects -->
+ <h:panelGroup rendered="#{not empty rdrs.siteName and rdrs.redirects.size() eq 0}">
+ <h2 class="initial">You have not set up any redirects.</h2>
+ <p class="initial">Redirect to an alternative site based on the device, browser or user preferences.</p>
+ <h:graphicImage class="initial" library="img" name="site-redirects.png" alt="Illustration: Arrow pointing from a laptop to a tablet and a smartphone" />
+ </h:panelGroup>
+
+ <h:panelGroup id="pgRedirectSummary" rendered="#{rdrs.redirects.size() > 0}">
+ <table id="redirect-table" class="table table-striped">
+ <thead id="redirect-summary-header" class="redirect-summary">
+ <tr>
+ <th>Status</th>
+ <th>Redirect name</th>
+ <th>Configurations</th>
+ <th class="actions hidden-element">Actions</th>
+ </tr>
+ </thead>
+ <tbody>
+ <ui:repeat value="#{rdrs.redirects}" var="r" varStatus="status">
+ <!-- Redirect Summary Row -->
+ <tr id="rdr_sum_#{status.index}" class="redirect-summary">
+ <td>
+ <div class="onoffswitch">
+ <h:selectBooleanCheckbox id="rdr_toggle" styleClass="onoffswitch-checkbox" value="#{r.isEnabled()}" />
+ <h:outputLabel for="rdr_toggle" styleClass="onoffswitch-label">
+ <f:ajax event="click" render="@this" listener="#{rdrEdit.toggleEnabled(rdrs.siteName, r.name)}" />
+ <span class="onoffswitch-inner">
+ <span class="onoffswitch-active">ON</span>
+ <span class="onoffswitch-inactive">OFF</span>
+ </span>
+ <span class="onoffswitch-switch"></span>
+ </h:outputLabel>
+ </div>
+ </td>
+ <td>#{r.name}</td>
+ <td>Redirect to #{r.redirectSite} <span class="second-info">#{r.conditions.size()} conditions and #{r.mappings.mappings.size()} mappings</span></td>
+ <td class="actions" style="text-align: center;">
+ <h:commandLink styleClass="configure-redirect redirect-summary">
+ <f:ajax event="action" render=":edit_form" listener="#{rdrEdit.load(rdrs.siteName, r.name)}" />
+ <i class="icon-wrench tooltipTrigger" data-original-title="Configure">Configure</i>
+ </h:commandLink>
+ <h:commandLink styleClass="deletee-redirect redirect-summary">
+ <f:ajax event="action" render=":edit_form" listener="#{rdrEdit.deleteRedirect(rdrs.siteName, r.name)}" />
+ <i class="icon-trash tooltipTrigger" data-original-title="Delete Redirect">Delete Redirect</i>
+ </h:commandLink>
+ </td>
+ </tr>
+ </ui:repeat>
+ </tbody>
+ </table>
+ </h:panelGroup>
+ </h:form>
+
+ <!-- Edit Redirect Table -->
+ <h:form id="edit_form" styleClass="form-horizontal">
+ <h:panelGroup id="edit_group" styleClass="edit-group" style="display: none;">
+ <table id="edit_redirect-table" class="table table-striped">
+ <tbody>
+ <tr style="display: none;"><td></td></tr>
+ <tr id="redirect_cfg" class="form-site-redirect">
+ <td colspan="4" style="padding-top: 10px;">
+ <fieldset class="header-site-redirect">
+ <legend class="hidden-element">
+ <span>General Settings</span>
+ </legend>
+ <div class="onoffswitch">
+ <h:selectBooleanCheckbox name="onoffswitch" styleClass="onoffswitch-checkbox" id="redirect3" value="#{rdrEdit.enabled}"/>
+ <h:outputLabel for="redirect3" styleClass="onoffswitch-label">
+ <span class="onoffswitch-inner">
+ <span class="onoffswitch-active">ON</span>
+ <span class="onoffswitch-inactive">OFF</span>
+ </span>
+ <span class="onoffswitch-switch"></span>
+ </h:outputLabel>
+ </div>
+ <div class="control-group">
+ <h:outputLabel for="name" styleClass="control-label">Redirect Name</h:outputLabel>
+ <div class="controls">
+ <b:input scale="medium" style="margin-left: -45px;" id="name" placeholder="Redirect Name" value="#{rdrEdit.name}" />
+ </div>
+ </div>
+ <div class="control-group">
+ <h:outputLabel for="redirect" style="margin-left: 65px;" styleClass="control-label">Redirect to</h:outputLabel>
+ <div class="controls">
+ <h:selectOneMenu id="redirect" value="#{rdrEdit.redirectSite}" style="height: 30px; line-height: 30px;">
+ <f:selectItems value="#{rdrs.sites}" var="site" itemLabel="#{site.name}" itemValue="#{site.name}" itemDisabled="#{site.name eq rdrs.siteName}" />
+ <f:ajax listener="#{rdrEdit.loadRedirectNodes}" />
+ </h:selectOneMenu>
+ </div>
+ </div><!-- End .control-group -->
+ </fieldset>
+ <fieldset>
+ <legend>
+ <span class="toggle">Conditions</span>
+ </legend>
+ <div>
+ <h:panelGroup id="conditions-group" styleClass="control-group">
+ <div class="controls">
+ <b:commandButton styleClass="btn btn-small inside-table add-condition" value="Add Condition" action="#{rdrEdit.addCondition}" oncomplete="$('#modal-condition').modal('show');" execute="@this" render=":condition_form" />
+ <table class="table table-striped button-small">
+ <thead style="#{empty rdrEdit.conditions ? 'display: none;' : ''}">
+ <tr>
+ <th>Condition Name</th>
+ <th>Settings</th>
+ <th class="hidden-element actions">Actions</th>
+ </tr>
+ </thead>
+ <tbody class="sortable">
+ <ui:repeat value="#{rdrEdit.conditions}" var="rc" varStatus="rc_st">
+ <tr class="ui-state-default">
+ <td>#{rc.name}</td>
+ <td>
+ <ui:repeat value="#{rc.userAgentConditions.contains}" var="rcUACcont" varStatus="cnt_st">
+ <h:panelGroup rendered="#{cnt_st.first}">
+ <strong>Contains </strong>
+ </h:panelGroup>
+ <h:panelGroup rendered="#{not cnt_st.first}">
+ OR
+ </h:panelGroup>
+ '#{rcUACcont}'
+ </ui:repeat>
+ <ui:repeat value="#{rc.userAgentConditions.doesNotContain}" var="rcUACnotcont" varStatus="dnc_st">
+ <h:panelGroup rendered="#{dnc_st.first}">
+ <strong>Does not contain </strong>
+ </h:panelGroup>
+ <h:panelGroup rendered="#{not dnc_st.first}">
+ OR
+ </h:panelGroup>
+ '#{rcUACnotcont}'
+ </ui:repeat>
+ </td>
+ <td class="actions">
+ <a4j:commandLink styleClass="add-condition" render=":condition_form" execute="@this" oncomplete="$('#modal-condition').modal()"><a4j:param value="#{rc_st.index}" assignTo="#{rdrEdit.currentConditionIndex}" /><f:setPropertyActionListener target="#{rdrEdit.editedCondition}" value="#{rc}" /><i class="icon-pencil tooltipTrigger" data-original-title="Edit Condition">Edit Condition</i></a4j:commandLink>
+ <a4j:commandLink action="#{rdrEdit.removeCondition(rc_st.index)}" styleClass="tooltipTrigger" title="Delete Condition" render="conditions-group" onclick="$(this).tooltip('hide');"><i class="icon-trash">Delete Condition</i></a4j:commandLink>
+ </td>
+ </tr>
+ </ui:repeat>
+ </tbody>
+ </table>
+ </div>
+ </h:panelGroup><!-- End .control-group -->
+ </div>
+ </fieldset>
+ <fieldset>
+ <legend>
+ <span class="toggle">Node Mappings</span>
+ </legend>
+ <div>
+ <div class="control-group">
+ <label for="matching" class="control-label">Matching</label>
+ <div class="controls">
+ <label class="checkbox">
+ <h:selectBooleanCheckbox name="matching" id="matching" value="#{rdrEdit.useNodeNameMatching}"/>Use node name matching
+ <i class="icon-info-sign icon-gray tooltipTrigger" title="Origin Node Name matches Redirect Node Name" data-placement="right">Origin Node Name matches Redirect Node Name</i>
+ </label>
+ </div>
+ </div><!-- End .control-group -->
+ <h:panelGroup layout="block" id="mappingsWrapper" styleClass="control-group">
+ <label class="control-label">Mappings</label>
+ <div class="controls">
+ <a4j:commandLink action="#{rdrEdit.addNodeMapping}" styleClass="btn btn-small inside-table" render="mappingsWrapper" oncomplete="$('.origin-node-name-input').last().focus();">Add Mapping</a4j:commandLink>
+ <table class="table table-striped action-button" id="mappings">
+ <thead style="#{empty rdrEdit.mappings.mappings ? 'display: none;' : ''}">
+ <tr>
+ <th>Origin Node Name</th>
+ <th>Redirect Node Name</th>
+ <th class="hidden-element actions">Actions</th>
+ </tr>
+ </thead>
+ <tbody id="mappings-tbody">
+ <ui:repeat value="#{rdrEdit.mappings.mappings}" var="m" varStatus="counter">
+ <tr class="node-mapping-viewer #{empty m.originNode or empty m.redirectNode ? 'hidden-element' : ''}">
+ <td>#{m.originNode}</td>
+ <td>#{m.redirectNode}</td>
+ <td class="actions">
+ <a href="#" class="edit-node-mapping tooltipTrigger" data-original-title="Edit Node Mapping" onclick="editMappingEntry(this)"><i class="icon-pencil">Edit Node Mapping</i></a>
+ <a4j:commandLink action="#{rdrEdit.removeNodeMapping(counter.index)}" styleClass="tooltipTrigger" title="Delete Node Mapping" render="mappingsWrapper" onclick="$(this).tooltip('hide'); return false;"><i class="icon-trash">Delete Node Mapping</i></a4j:commandLink>
+ </td>
+ </tr>
+ <!-- Just so that we keep the odd/even colors -->
+ <tr class="node-mapping-spacer" style="display: none;"><td></td></tr>
+ <tr class="node-mapping-editor #{empty m.originNode or empty m.redirectNode ? '' : 'hidden-element'}">
+ <td>
+ <b:input scale="medium" placeholder="e.g. homepage" value="#{m.originNode}" styleClass="origin-node-name-input">
+ <!-- <b:autocomplete suggestions="#{rdrEdit.originNodeNames}" /> -->
+ <f:facet name="append">
+ <b:commandButton styleClass="tooltipTrigger select-node" title="View Node List" style="width: 40px; margin-left: -5px;" render="modal-select-node-wrapper" onclick="nodeInput = $(this).prev('input')" oncomplete="showNodeList()" action="#{rdrEdit.setCurrentNodeNames(true)}"><i class="icon-list" ></i></b:commandButton>
+ </f:facet>
+ </b:input>
+ </td>
+ <td>
+ <b:input scale="medium" placeholder="e.g. home_page" value="#{m.redirectNode}" styleClass="redirect-node-name-input">
+ <!-- <b:autocomplete suggestions="#{rdrEdit.redirectNodeNames}" /> -->
+ <f:facet name="append">
+ <b:commandButton styleClass="tooltipTrigger select-node" title="View Node List" style="width: 40px; margin-left: -5px;" render="modal-select-node-wrapper" onclick="nodeInput = $(this).prev('input')" oncomplete="showNodeList()" action="#{rdrEdit.setCurrentNodeNames(false)}"><i class="icon-list" ></i></b:commandButton>
+ </f:facet>
+ </b:input>
+ </td>
+ <td class="actions">
+ <a href="#" class="delete-node-mapping tooltipTrigger" title="Delete Node Mapping" onclick="deleteMappingEntry(this); return false;"><i class="icon-trash">Delete Node Mapping</i></a>
+ </td>
+ </tr>
+ </ui:repeat>
+ </tbody>
+ </table>
+ </div>
+ </h:panelGroup><!-- End .control-group -->
+ <div class="control-group">
+ <label class="control-label" for="nodes">Unresolved nodes</label>
+ <div class="controls">
+ <h:selectOneMenu id="nodes" style="height: 30px; line-height: 30px;" value="#{rdrEdit.mappings.unresolvedNode}">
+ <f:selectItem itemValue="REDIRECT" itemLabel="Redirect" />
+ <f:selectItem itemValue="NO_REDIRECT" itemLabel="No Redirect" />
+ <f:selectItem itemValue="ROOT" itemLabel="Redirect to root" />
+ <f:selectItem itemValue="COMMON_ANCESTOR_NAME_MATCH" itemLabel="Ancestor Name Match" />
+ </h:selectOneMenu>
+ </div>
+ </div><!-- End .control-group -->
+ </div>
+ </fieldset>
+ <div class="form-actions" style="background: none;">
+ <button id="edit_cancel" class="btn" type="submit">Cancel</button>
+ <b:commandButton value="Save changes" styleClass="btn btn-primary" action="#{rdrEdit.saveRedirect}" render="pgRedirectSummary" oncomplete="closeRedirectEdit()"/>
+ </div><!-- End .form-actions -->
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </h:panelGroup>
+ </h:form><!-- End .form-horizontal -->
+
+ <script type="text/javascript">
+ $(document).ready(function(){
+ var nodeInput = null;
+ });
+ </script>
+
+ <ui:include src="/admin/redirects/modals/modals.xhtml" />
+ <ui:include src="/admin/redirects/modals/modal-condition.xhtml" />
+ <ui:include src="/admin/redirects/modals/modal-select_node.xhtml" />
+ <ui:include src="/admin/redirects/modals/modal-delete_site.xhtml" />
+ <ui:include src="/admin/redirects/modals/modal-import_site.xhtml" />
+
+ </ui:define>
+</ui:composition>
View
44 portlet/admin/redirect/src/main/webapp/admin/redirects/menu.xhtml
@@ -0,0 +1,44 @@
+<ui:fragment xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:rich="http://richfaces.org/rich"
+ xmlns:a4j="http://richfaces.org/a4j"
+ xmlns:b="http://richfaces.org/sandbox/bootstrap">
+
+ <h:form id="menu_form">
+ <nav id="local-nav" style="margin-top: 25px;">
+ <ul class="nav nav-list">
+ <li id="sites"> <!-- Sites List / begin -->
+ <div>
+ <span class="toggle">Redirects</span>
+ <h:panelGroup styleClass="more" rendered="#{rdrs.sites.size() > 4}">Show more</h:panelGroup>
+ </div>
+ <ul>
+ <ui:repeat value="#{rdrs.sites}" var="s" varStatus="counter">
+ <li class="dropdown #{rdrs.siteName == s.name ? 'active' : ''} #{counter.index > 3 ? 'extra hidden-element' : ''}">
+ <a4j:commandLink action="#{rdrs.setSiteName(s.name)}" styleClass="site-link" onclick="$('.edit-group').hide();" render="@form :sum_form :add_form :form-select-node">
+ <b:icon value="globe" color="grey" /> #{s.name}
+ </a4j:commandLink>
+ <!-- For now, no Export or Delete option
+ <span class="dropdown-toggle" data-toggle="dropdown"><i class="icon-opened icon-gray">View actions...</i></span>
+ <ul class="dropdown-menu">
+ <li><a href="#">Export Site</a></li>
+ <li class="delete-site separator"><a href="#">Delete Site</a></li>
+ </ul>
+ -->
+ </li>
+ </ui:repeat>
+ </ul>
+ </li> <!-- Sites List / end -->
+ <!-- For now, no Import option
+ <li id="server">
+ <ul>
+ <li><a href="#" class="import-site" id="import-site"><i class="icon-download-alt icon-gray"></i> Import Site</a></li>
+ </ul>
+ </li>
+ -->
+ </ul>
+ </nav>
+ </h:form>
+</ui:fragment>
View
169 portlet/admin/redirect/src/main/webapp/admin/redirects/modals/modal-condition.xhtml
@@ -0,0 +1,169 @@
+<ui:fragment xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:rich="http://richfaces.org/rich"
+ xmlns:a4j="http://richfaces.org/a4j"
+ xmlns:b="http://richfaces.org/sandbox/bootstrap">
+
+ <h:form id="condition_form">
+ <div class="modal confirmation hide" id="modal-condition">
+ <h:panelGroup layout="block" id="modal-condition-wrapper">
+ <div class="modal-header">
+ <button class="close" data-dismiss="modal">Close</button>
+ <h3>Add Condition</h3>
+ </div>
+ <div class="modal-body">
+ <p class="subtitle">All fields are required</p>
+ <div class="control-group">
+ <label class="control-label" for="condition_name">Condition Name </label>
+ <b:input mode="client" styleClass="input-large" required="true" requiredMessage="Value required" id="condition_name" value="#{rdrEdit.editedCondition.name}" placeholder="Condition Name" onkeyup="validateCondition()">
+ </b:input>
+ <h:message id="condition_name-message" for="condition_name" />
+ </div><!-- End .control-group -->
+ <div class="control-group">
+ <h:panelGroup id="uasHolder">
+ <table class="table table-striped" id="condition-string">
+ <thead>
+ <tr>
+ <th>User Agent String</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>
+ <label>Contains</label>
+ <ui:param name="isContainsEmpty" value="#{rdrEdit.editedCondition == null or rdrEdit.editedCondition.userAgentConditions == null or rdrEdit.editedCondition.userAgentConditions.contains == null or rdrEdit.editedCondition.userAgentConditions.contains.size() == 0}" />
+ <ui:repeat value="#{rdrEdit.editedCondition.userAgentConditions.contains}" var="rcUACcont" varStatus="counter">
+ <div class="#{counter.index > 0 ? 'more-condition' : 'condition'}">
+ <h:panelGroup styleClass="td-condition" rendered="#{counter.index > 0}">OR</h:panelGroup>
+ <b:input id="rcuaccont" styleClass="contains-input" value="#{rdrEdit.editedCondition.userAgentConditions.contains[counter.index]}" placeholder="eg: (?i)i(phone|pad|pod)" />
+ <div class="action">
+ <a4j:commandLink action="#{rdrEdit.removeContains(counter.index)}" styleClass="tooltipTrigger" title="Delete Condition" render="uasHolder" onclick="$(this).tooltip('hide');"><i class="icon-trash">Delete User Agent Condition</i></a4j:commandLink>
+ <a4j:commandLink action="#{rdrEdit.addContains}" styleClass="add-user-agent-string tooltipTrigger" title="Add Condition" render="uasHolder" onclick="$(this).tooltip('hide');" oncomplete="$('.contains-input').last().focus();" style="#{counter.last ? '' : 'visibility: hidden;'}"><i class="icon-plus-sign">Add User Agent Condition</i></a4j:commandLink>
+ </div>
+ </div>
+ </ui:repeat>
+ <div class="#{isContainsEmpty ? 'condition' : 'more-condition'}" style="#{isContainsEmpty ? '' : 'display: none;'}">
+ <h:panelGroup styleClass="td-condition" rendered="#{not isContainsEmpty}">OR</h:panelGroup>
+ <h:inputText id="rcuaccont" style="visibility: hidden;"/>
+ <div class="action">
+ <a4j:commandLink style="visibility: hidden;" action="#{rdrEdit.removeContains(counter.index)}" styleClass="tooltipTrigger" title="Delete Condition" render="uasHolder" onclick="$(this).tooltip('hide');"><i class="icon-trash">Delete User Agent Condition</i></a4j:commandLink>
+ <a4j:commandLink action="#{rdrEdit.addContains}" styleClass="add-user-agent-string tooltipTrigger" title="Add Condition" render="uasHolder" onclick="$(this).tooltip('hide');" oncomplete="$('.contains-input').last().focus();"><i class="icon-plus-sign">Add User Agent Condition</i></a4j:commandLink>
+ </div>
+ </div>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <label>Does not contain</label>
+ <ui:param name="isDoesNotContainEmpty" value="#{rdrEdit.editedCondition == null or rdrEdit.editedCondition.userAgentConditions == null or rdrEdit.editedCondition.userAgentConditions.doesNotContain == null or rdrEdit.editedCondition.userAgentConditions.doesNotContain.size() == 0}" />
+ <ui:repeat value="#{rdrEdit.editedCondition.userAgentConditions.doesNotContain}" var="rcUACdncont" varStatus="counter">
+ <div class="#{counter.index == 0 ? 'condition' : 'more-condition'}">
+ <h:panelGroup styleClass="td-condition" rendered="#{counter.index > 0}">OR</h:panelGroup>
+ <b:input id="rcuacdncont" styleClass="doesnotcontain-input" value="#{rdrEdit.editedCondition.userAgentConditions.doesNotContain[counter.index]}" placeholder="eg: (?i)i(phone|pad|pod)" />
+ <div class="action">
+ <a4j:commandLink action="#{rdrEdit.removeDoesNotContain(counter.index)}" styleClass="tooltipTrigger" title="Delete Condition" render="uasHolder" onclick="$(this).tooltip('hide');"><i class="icon-trash">Delete User Agent Condition</i></a4j:commandLink>
+ <a4j:commandLink action="#{rdrEdit.addDoesNotContain}" styleClass="add-user-agent-string tooltipTrigger" title="Add Condition" render="uasHolder" onclick="$(this).tooltip('hide');" oncomplete="$('.doesnotcontain-input').last().focus();" style="#{counter.last ? '' : 'visibility: hidden;'}"><i class="icon-plus-sign">Add User Agent Condition</i></a4j:commandLink>
+ </div>
+ </div>
+ </ui:repeat>
+ <div class="#{isDoesNotContainEmpty ? 'condition' : 'more-condition'}" style="#{isDoesNotContainEmpty ? '' : 'display: none;'}">
+ <h:panelGroup styleClass="td-condition" rendered="#{not isDoesNotContainEmpty}">OR</h:panelGroup>
+ <h:inputText id="rcuacdncont" style="visibility: hidden;" />
+ <div class="action">
+ <a4j:commandLink style="visibility: hidden;" action="#{rdrEdit.removeDoesNotContain(counter.index)}" styleClass="tooltipTrigger" title="Delete Condition" render="uasHolder" onclick="$(this).tooltip('hide');"><i class="icon-trash">Delete User Agent Condition</i></a4j:commandLink>
+ <a4j:commandLink action="#{rdrEdit.addDoesNotContain}" styleClass="add-user-agent-string tooltipTrigger" title="Add Condition" render="uasHolder" onclick="$(this).tooltip('hide');" oncomplete="$('.doesnotcontain-input').last().focus();"><i class="icon-plus-sign">Add User Agent Condition</i></a4j:commandLink>
+ </div>
+ </div>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </h:panelGroup>
+ </div><!-- End .control-group -->
+
+ <h:panelGroup id="condition_properties" styleClass="control-group">
+ <h:panelGroup style="#{rdrEdit.editedCondition.deviceProperties == null or rdrEdit.editedCondition.deviceProperties.size() == 0 ? '' : 'display:none;'}">
+ <a4j:commandLink action="#{rdrEdit.addProperty}" styleClass="btn btn-mini pull-right" render="condition_properties" oncomplete="$('.property-name-input').last().focus();">Add Properties</a4j:commandLink>
+ </h:panelGroup>
+ <table class="table table-striped button-mini" id="condition-properties" style="#{rdrEdit.editedCondition.deviceProperties == null ? 'display: none;' : ''}">
+ <thead>
+ <tr>
+ <th>Property</th>
+ <th class="hidden-element actions">Actions</th>
+ </tr>
+ </thead>
+ <tbody>
+ <ui:repeat value="#{rdrEdit.editedCondition.deviceProperties}" var="rcDevProp" varStatus="counter">
+ <tr>
+ <td class="condition" colspan="2">
+ <ui:param name="rcDevPropOp" value="#{rcDevProp.equals != null ? 'eq' : rcDevProp.greaterThan != null ? (rcDevProp.lessThan != null ? 'bt' : 'gt') : rcDevProp.lessThan != null ? 'lt' : 'mt'}" />
+ <h:inputText id="name-rcDevProp" styleClass="property property-name-input" value="#{rdrEdit.editedCondition.deviceProperties[counter.index].propertyName}" />
+ <!-- For some reason this causes the components to stop working.. using pure HTML
+ <h:selectOneMenu id="op-rcDevProp" styleClass="attribute" style="height: 30px;" onchange="propertyFields(this);" value="#{rdrEdit.getPropertyOperator(counter.index)}">
+ <f:selectItem id="eq" itemLabel="Equals" itemValue="eq" />
+ <f:selectItem id="gt" itemLabel="Greater than" itemValue="gt" />
+ <f:selectItem id="lt" itemLabel="Less than" itemValue="lt" />
+ <f:selectItem id="bt" itemLabel="Between" itemValue="bt" />
+ <f:selectItem id="mt" itemLabel="Matches" itemValue="mt" />
+ </h:selectOneMenu>
+ -->
+ <select id="op-rcDevProp" class="attribute" style="height: 30px;" onchange="changePropertyFields(this);" >
+ <option value="eq" selected='#{rcDevPropOp == "eq" ? "selected" : ""}'>Equals</option>
+ <option value="gt" selected='#{rcDevPropOp == "gt" ? "selected" : ""}'>Greater than</option>
+ <option value="lt" selected='#{rcDevPropOp == "lt" ? "selected" : ""}'>Less than</option>
+ <option value="mt" selected='#{rcDevPropOp == "mt" ? "selected" : ""}'>Matches</option>
+ <option value="bt" selected='#{rcDevPropOp == "bt" ? "selected" : ""}'>Between</option>
+ </select>
+ <span id="value-holder">
+ <h:panelGroup styleClass="pp-bt" style="#{rcDevPropOp == 'bt' ? '' : 'display:none'}">
+ <div class="input-append-inline">
+ <h:inputText id="val-rcDevProp_bt_gt" styleClass="property-value-input" value="#{rdrEdit.editedCondition.deviceProperties[counter.index].greaterThan}" />
+ </div>
+ <span class="td-condition">AND</span>
+ <div class="input-append-inline">
+ <h:inputText id="val-rcDevProp_bt_lt" value="#{rdrEdit.editedCondition.deviceProperties[counter.index].lessThan}" />
+ </div>
+ </h:panelGroup>
+ <h:panelGroup styleClass="pp-eq" style="#{rcDevPropOp == 'eq' ? '' : 'display:none'}">
+ <div class="input-append-inline">
+ <h:inputText id="val-rcDevProp_eq" styleClass="property-value-input" style="width: 128px;" value="#{rdrEdit.editedCondition.deviceProperties[counter.index].equals}" converter="PropertiesConverter" />
+ </div>
+ </h:panelGroup>
+ <h:panelGroup styleClass="pp-mt" style="#{rcDevPropOp == 'mt' ? '' : 'display:none'}">
+ <div class="input-append-inline">
+ <h:inputText id="val-rcDevProp_mt" styleClass="property-value-input" style="width: 128px;" value="#{rdrEdit.editedCondition.deviceProperties[counter.index].matches}" converter="PropertiesConverter" />
+ </div>
+ </h:panelGroup>
+ <h:panelGroup styleClass="pp-gt" style="#{rcDevPropOp == 'gt' ? '' : 'display:none'}">
+ <div class="input-append-inline">
+ <h:inputText id="val-rcDevProp_gt" styleClass="property-value-input" value="#{rdrEdit.editedCondition.deviceProperties[counter.index].greaterThan}" />
+ </div>
+ </h:panelGroup>
+ <h:panelGroup styleClass="pp-lt" style="#{rcDevPropOp == 'lt' ? '' : 'display:none'}">
+ <div class="input-append-inline">
+ <h:inputText id="val-rcDevProp_lt" styleClass="property-value-input" value="#{rdrEdit.editedCondition.deviceProperties[counter.index].lessThan}" />
+ </div>
+ </h:panelGroup>
+ </span>
+ </td>
+ <td class="actions" style="width: 50px;" >
+ <a4j:commandLink action="#{rdrEdit.removeProperty(counter.index)}" styleClass="tooltipTrigger" title="Delete Property" render="condition_properties" onclick="$(this).tooltip('hide');"><i class="icon-trash">Delete Property</i></a4j:commandLink>
+ <a4j:commandLink action="#{rdrEdit.addProperty}" styleClass="add-property tooltipTrigger" title="Add Property" render="condition_properties" onclick="$(this).tooltip('hide');" style="#{counter.last ? '' : 'visibility: hidden;'}"><i class="icon-plus-sign">Add Property</i></a4j:commandLink>
+ </td>
+ </tr>
+ </ui:repeat>
+ </tbody>
+ </table>
+ </h:panelGroup><!-- End .control-group -->
+ </div><!-- End .modal-body -->
+ <h:panelGroup layout="block" id="condition_footer" styleClass="modal-footer">
+ <b:commandButton value="Cancel" action="#{rdrEdit.rollbackCondition}" oncomplete="$('#modal-condition').modal('hide');" execute="@form" />
+ <b:commandButton id="save-condition-button" value="Save Changes!" styleClass="btn btn-primary" action="#{rdrEdit.saveCondition}" execute="@form" oncomplete="$('#modal-condition').modal('hide');" render="conditions-group" />
+ </h:panelGroup>
+ </h:panelGroup><!-- end .modal -->
+ </div><!-- end .modal -->
+ </h:form>
+
+</ui:fragment>
View
30 portlet/admin/redirect/src/main/webapp/admin/redirects/modals/modal-delete_site.xhtml
@@ -0,0 +1,30 @@
+<ui:fragment xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:rich="http://richfaces.org/rich"
+ xmlns:a4j="http://richfaces.org/a4j"
+ xmlns:b="http://richfaces.org/sandbox/bootstrap">
+
+ <h:form id="form-delete-site">
+ <input type="hidden" id="delete-site-id-input" name="delete-site-id-input" value="UNDEFINED"/>
+ <div class="modal hide" id="modal-delete-site">
+ <div class="modal-header">
+ <button class="close" data-dismiss="modal">Close</button>
+ <h3>Delete Site</h3>
+ </div>
+ <div class="modal-body">
+ <p>
+ <strong>Are you sure you want to permanently delete the site "<span id="delete-site-id-text">UNDEFINED</span>" ?</strong>
+ <br />
+ <span>You can't undo this action.</span>
+ </p>
+ </div><!-- End .modal-body -->
+ <div class="modal-footer">
+ <a href="#" class="btn" data-dismiss="modal" aria-hidden="true">Cancel</a>
+ <a href="#" id="button-select-node" class="btn btn-danger">Delete Site</a>
+ </div>
+ </div><!-- end .modal -->
+ </h:form>
+
+</ui:fragment>
View
41 portlet/admin/redirect/src/main/webapp/admin/redirects/modals/modal-import_site.xhtml
@@ -0,0 +1,41 @@
+<ui:fragment xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:rich="http://richfaces.org/rich"
+ xmlns:a4j="http://richfaces.org/a4j"
+ xmlns:b="http://richfaces.org/sandbox/bootstrap">
+
+ <h:form id="form-import-site">
+ <div class="modal hide" id="modal-import-site">
+ <div class="modal-header">
+ <button class="close" data-dismiss="modal">Close</button>
+ <h3>Import Site</h3>
+ </div>
+ <div class="modal-body">
+ <div id="file-input-holder" class="control-group">
+ <label class="control-label" for="file">File to import </label>
+ <input type="file" class="input-xlarge" id="file" />
+ <div id="file-attachment" class="attachment" style="display: none;">
+ <span id="fileName" class="text-side-label">UNDEFINED</span>
+ <button id="file-remove-btn"><i class="icon-remove"> Delete File</i></button>
+ </div>
+ </div><!-- End .control-group -->
+ <div class="control-group">
+ <label class="control-label" for="mode">Import Mode </label>
+ <select id="mode">
+ <option>Conserve</option>
+ <option>Insert</option>
+ <option selected="selected">Merge</option>
+ <option>Overwrite</option>
+ </select>
+ </div><!-- End .control-group -->
+ </div><!-- End .modal-body -->
+ <div class="modal-footer">
+ <a href="#" class="btn" data-dismiss="modal" aria-hidden="true">Cancel</a>
+ <a href="#" id="button-import-site" class="btn btn-primary">Import</a>
+ </div>
+ </div><!-- end .modal -->
+ </h:form>
+
+</ui:fragment>
View
33 portlet/admin/redirect/src/main/webapp/admin/redirects/modals/modal-select_node.xhtml
@@ -0,0 +1,33 @@
+<ui:fragment xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:rich="http://richfaces.org/rich"
+ xmlns:a4j="http://richfaces.org/a4j"
+ xmlns:b="http://richfaces.org/sandbox/bootstrap">
+
+ <h:form id="form-select-node">
+ <div class="modal hide" id="modal-select-node">
+ <h:panelGroup layout="block" id="modal-select-node-wrapper">
+ <div class="modal-header">
+ <button class="close" data-dismiss="modal">Close</button>
+ <h3>Select Node - #{rdrEdit.currentNodesSiteName}</h3>
+ </div>
+ <div class="modal-body">
+ <div class="window-list">
+ <ul class="clearfix">
+ <ui:repeat value="#{rdrEdit.currentNodeNames}" var="n" varStatus="status">
+ <li><label for="#{n}" class="#{status.first ? 'active' : ''}"><input class="radio-node" type="radio" id="#{n}" name="user-group" checked="#{status.first ? 'checked' : ''}"/>#{n}</label></li>
+ </ui:repeat>
+ </ul>
+ </div><!-- End .windowList -->
+ </div><!-- End .modal-body -->
+ <div class="modal-footer">
+ <a href="#" class="btn" data-dismiss="modal" aria-hidden="true">Cancel</a>
+ <a href="#" id="button-select-node" class="btn btn-primary" onclick="selectNodeFromList(); return false;">Select this node</a>
+ </div>
+ </h:panelGroup>
+ </div><!-- end .modal -->
+ </h:form>
+
+</ui:fragment>
View
52 portlet/admin/redirect/src/main/webapp/admin/redirects/modals/modals.xhtml
@@ -0,0 +1,52 @@
+<ui:fragment xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:rich="http://richfaces.org/rich"
+ xmlns:a4j="http://richfaces.org/a4j"
+ xmlns:b="http://richfaces.org/sandbox/bootstrap">
+
+ <!-- Injected elements -->
+
+ <div class="alert-container hidden-element">
+ <div class="alert alert-success">
+ <button data-dismiss="alert" class="close">Close</button>
+ <strong>Well done!</strong> The redirect has been successfully deleted.
+ </div><!-- End .alert -->
+ </div>
+
+ <div class="modal confirmation hide" id="modal-delete-site-space">
+ <div class="modal-header">
+ <button data-dismiss="modal" class="close" type="button">Close</button>
+ <h3>Delete Site</h3>
+ </div>
+ <div class="modal-body">
+ <p>
+ <strong>Are you sure you want to permanently delete this site?</strong>
+ <span>You can't undo this action.</span>
+ </p>
+ </div><!-- End .modal-body -->
+ <div class="modal-footer">
+ <a href="#" class="btn">Cancel</a>
+ <a href="#" class="btn btn-primary">Delete this site</a>
+ </div>
+ </div><!-- end .modal -->
+
+ <div class="modal confirmation hide" id="modal-delete-redirect">
+ <div class="modal-header">
+ <button data-dismiss="modal" class="close" type="button">Close</button>
+ <h3>Delete Redirect</h3>
+ </div>
+ <div class="modal-body">
+ <p>
+ <strong>Are you sure you want to permanently delete this redirect?</strong>
+ <span>You can't undo this action.</span>
+ </p>
+ </div><!-- End .modal-body -->
+ <div class="modal-footer">
+ <a href="#" class="btn">Cancel</a>
+ <a href="#" class="btn btn-primary">Delete this redirect</a>
+ </div>
+ </div><!-- end .modal -->
+
+</ui:fragment>
View
302 portlet/admin/redirect/src/main/webapp/resources/css/admin-responsive.css
@@ -0,0 +1,302 @@
+/* General styles */
+
+@media (min-width: 1200px) {
+
+ #actions-bg {width: 1150px;}
+
+ #container-right-bg {
+ margin-left: 300px;
+ width: 900px;
+ }
+
+ .span9 {
+ width: 840px;
+ padding-left: 30px;
+ padding-right: 30px;
+ }
+
+ .initial {margin-left: 160px;}
+
+ .form-mobile-redirect .header-mobile-redirect .control-group,
+ .form-mobile-redirect .header-mobile-redirect .control-group:last-child {
+ width: 300px;
+ margin-left: 60px;
+ margin-bottom: 0;
+ }
+
+ .header-mobile-redirect input, .header-mobile-redirect select {width: 175px;}
+
+ tbody.sortable tr td:nth-child(1) {width: 150px;}
+ tbody.sortable tr td:nth-child(2) {width: 420px;}
+ tbody.sortable tr td:nth-child(3v) {width: 130px;}
+
+ #mappings .input-medium {width: 149px;}
+
+ footer {width: 1170px;}
+
+ footer p {margin-left: 300px;}
+
+ footer > ul {margin-right: 25px;}
+
+}
+
+@media (min-width: 768px) and (max-width: 979px) {
+
+ body {padding-top: 0;}
+
+ /* Topbar */
+
+ .navbar-fixed-top {
+ margin-bottom: 2px;
+ position: fixed;
+ }
+
+ .navbar-fixed-top .navbar-inner {padding: 0;}
+
+ .navbar .container {width: 724px;}
+
+ .navbar .brand {margin-left: -20px;}
+
+ .nav-collapse {
+ height: auto;
+ overflow: visible;
+ clear: none;
+ }
+
+ .nav-collapse .nav {margin-bottom: 0;}
+
+ .navbar .nav-collapse .nav.pull-right {float: right;}
+
+ .nav-collapse .nav > li {float: left;}
+
+ .nav-collapse .nav > li > a {
+ font-weight: normal;
+ padding: 9px 10px 11px;
+ margin-bottom: 0;
+ }
+
+ /* Topbar dropdown */
+
+ .navbar .dropdown-menu {display: none;}
+
+ .open .dropdown-menu,
+ .open .dropdown-menu:before,
+ .open .dropdown-menu:after {display: block;}
+
+ .open .dropdown-menu {
+ background-color: #FFFFFF;
+ border: 1px solid rgba(0, 0, 0, 0.2);
+ border-radius: 5px 5px 5px 5px;
+ box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
+ margin: 1px 0 0;
+ padding: 4px 0;
+ position: absolute;
+ }
+
+ .nav-collapse .dropdown-menu a {
+ color: #333333;
+ line-height: 18px;
+ padding: 3px 15px;
+ border-radius: 0;
+ font-weight: normal;
+ }
+
+ .nav-collapse .dropdown-menu li > a:hover,
+ .nav-collapse .dropdown-menu .active > a,
+ .nav-collapse .dropdown-menu .active > a:hover {
+ background-color: #0088CC;
+ color: #FFFFFF;
+ text-decoration: none;
+ }
+
+ /* Aside */
+
+ .nav-list a#add-page {top: 15px;}
+
+ #actions-bg {width: 730px;}
+
+ /* Content */
+
+ .form-horizontal .control-label {width: 125px;}
+
+ .form-horizontal .controls {margin-left: 140px;}
+
+ #container-right-bg {
+ margin-left: 186px;
+ width: 558px;
+ }
+
+ .span9 {
+ width: 518px;
+ padding-left: 20px;
+ padding-right: 20px;
+ }
+
+ .initial {margin-left: 0;}
+
+ .header-mobile-redirect .control-group label {
+ width: 100px;
+ text-align: right;
+ }
+
+ .form-mobile-redirect .header-mobile-redirect .control-group {width: 300px;}
+
+ .form-mobile-redirect .header-mobile-redirect .control-group:last-child {
+ margin-left: 87px;
+ margin-top: 10px;
+ }
+
+ #mappings .input-medium {width: 85px;}
+
+ #space-group .top-actions .pull-right {
+ float: none;
+ clear: both;
+ margin-top: 15px;
+ }
+
+ .window-tree {width: 356px;}
+
+ /* Footer */
+
+ footer {
+ width: 724px;
+ height: 50px;
+ margin-top: -50px;
+ }
+
+ footer p {
+ margin-left: 186px;
+ float: none;
+ }
+
+ footer > ul {
+ margin-left: 173px;
+ float: none;
+ margin-top: 5px;
+ }
+
+
+}
+
+@media (max-width: 767px) {
+
+ body {
+ padding: 0;
+ background: #fff;
+ }
+
+ .navbar-fixed-top, .navbar-fixed-bottom {
+ margin-left: 0;
+ margin-right: 0;
+ }
+
+ /* Topbar */
+
+ .navbar-fixed-top {
+ position: absolute;
+ margin-bottom: 0;
+ }
+
+ .navbar-fixed-top .navbar-inner {padding: 0;}
+
+ .nav-collapse {
+ height: auto;
+ overflow: visible;
+ clear: none;
+ }
+
+ .nav-collapse .nav {margin-bottom: 0;}
+
+ .navbar .nav-collapse .nav.pull-right {float: right;}
+
+ .navbar #settings {display: none;}
+
+ .nav-collapse .nav > li {float: left;}
+
+ .nav-collapse .nav > li > a {
+ font-weight: normal;
+ padding: 9px 10px 11px;
+ margin-bottom: 0;
+ }
+
+ /* Topbar dropdown */
+
+ .navbar .dropdown-menu {display: none;}
+
+ .open .dropdown-menu,
+ .open .dropdown-menu:before,
+ .open .dropdown-menu:after {display: block;}
+
+ .open .dropdown-menu {
+ background-color: #FFFFFF;
+ border: 1px solid rgba(0, 0, 0, 0.2);
+ border-radius: 5px 5px 5px 5px;
+ box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
+ margin: 1px 0 0;
+ padding: 4px 0;
+ position: absolute;
+ }
+
+ .nav-collapse .dropdown-menu a {
+ color: #333333;
+ line-height: 18px;
+ padding: 3px 15px;
+ border-radius: 0;
+ font-weight: normal;
+ }
+
+ .nav-collapse .dropdown-menu li > a:hover,
+ .nav-collapse .dropdown-menu .active > a,
+ .nav-collapse .dropdown-menu .active > a:hover {
+ background-color: #0088CC;
+ color: #FFFFFF;
+ text-decoration: none;
+ }
+
+ /* */
+
+ #wrapper {margin-top: 40px;}
+
+ aside.span3,
+ #actions-bg,
+ #container-right-bg {display: none;}
+
+ .row {
+ padding-left: 20px;
+ padding-right: 20px;
+ }
+
+ #container-right {
+ box-shadow: none;
+ background: none;
+ padding-bottom: 74px;
+ margin-top: 0;
+ }
+
+ .span9 {
+ width: 100%;
+ padding: 0;
+ }
+
+ .input-large,
+ .input-xlarge,
+ .input-xxlarge,
+ input[class*="span"],
+ select[class*="span"],
+ textarea[class*="span"],
+ .uneditable-input {width: 80%;}
+
+ footer {
+ width: auto;
+ }
+
+ footer > ul,
+ footer >p {
+ margin-left: 20px;
+ }
+
+ footer ul li:first-child {
+ padding-left: 0;
+ margin-left: 0;
+ }
+}
View
1,274 portlet/admin/redirect/src/main/webapp/resources/css/admin.css
@@ -0,0 +1,1274 @@
+/* General styles */
+
+@font-face {
+ font-family: 'Ubuntu';
+ font-style: normal;
+ font-weight: 400;
+ src: local('Ubuntu'), url(http://themes.googleusercontent.com/static/fonts/ubuntu/v4/vRvZYZlUaogOuHbBTT1SNevvDin1pK8aKteLpeZ5c0A.woff) format('woff');
+}
+
+html,
+body,
+#wrap {height: 100%;}
+
+body > #wrap {
+ height: auto;
+ min-height: 100%;
+}
+
+/* ammendonca: not suitable for portal
+body {background: url("#{resource['/img/body-bg.jpg']}") repeat left top;}
+*/
+
+.link {
+ background: none;
+ border: none;
+ color: #1C5182;
+ padding: 0;
+}
+
+.link:hover {
+ color: #005580;
+ text-decoration: underline;
+}
+
+.icon-gray {background-image: url(#{resource['/img/glyphicons-halflings-gray.png']});}
+
+.gray {color: #999;}
+
+.dropdown-menu .disabled {color: #aaa;}
+
+.dropdown-menu .disabled:hover {
+ cursor: default;
+ background-color: transparent;
+ color: #aaa;
+ text-decoration: none;
+}
+
+.btn.disabled {cursor: default;}
+
+.btn.disabled,
+.btn[disabled],
+.btn.disabled:hover,
+.btn[disabled]:hover {background: #f0f0f0;}
+
+i {
+ text-indent: -99999px;
+ text-align: left;
+}
+
+a {color: #1c5182;}
+a:focus {outline: none;}
+a:hover {color: #285786;}
+
+button.close,
+a.close {
+ text-indent: -99999px;
+ display: inline-block;
+ width: 10px;
+ height: 12px;
+ background: url(#{resource['/img/icon-close.png']}) no-repeat left top;
+}
+
+input[type="file"] {
+ height: auto;
+ font-family: Helvetica, Arial, sans-serif;
+}
+
+.alert .close {top: 3px;}
+
+h1