You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@rave.apache.org by mf...@apache.org on 2014/07/03 18:46:44 UTC

[50/50] git commit: Merged master into branch

Merged master into branch


Project: http://git-wip-us.apache.org/repos/asf/rave/repo
Commit: http://git-wip-us.apache.org/repos/asf/rave/commit/5344cc71
Tree: http://git-wip-us.apache.org/repos/asf/rave/tree/5344cc71
Diff: http://git-wip-us.apache.org/repos/asf/rave/diff/5344cc71

Branch: refs/heads/angular
Commit: 5344cc71164cf5311af3a5a5f9a62af93a2b870f
Parents: 60e6ed5 1e068c5
Author: Matt Franklin <mf...@apache.org>
Authored: Thu Jul 3 12:45:43 2014 -0400
Committer: Matt Franklin <mf...@apache.org>
Committed: Thu Jul 3 12:45:43 2014 -0400

----------------------------------------------------------------------
 .gitignore                                      |   4 +
 LICENSE                                         |  27 ++
 pom.xml                                         |   7 +-
 rave-components/pom.xml                         |   2 +-
 rave-components/rave-commons/pom.xml            |   2 +-
 rave-components/rave-core-api/pom.xml           |   2 +-
 .../org/apache/rave/model/ApplicationData.java  |  12 +-
 .../main/java/org/apache/rave/model/Page.java   |  31 ++
 .../org/apache/rave/model/PageTemplate.java     |  17 +
 .../main/java/org/apache/rave/model/Widget.java |  17 +
 .../org/apache/rave/rest/GroupsResource.java    |  50 +++
 .../apache/rave/rest/OrganizationsResource.java |  50 +++
 .../apache/rave/rest/PageTemplatesResource.java |  66 ++++
 .../org/apache/rave/rest/PagesResource.java     |  14 +-
 .../org/apache/rave/rest/WidgetsResource.java   |  74 ++++
 .../java/org/apache/rave/rest/model/Group.java  |  22 ++
 .../apache/rave/rest/model/Organization.java    |  22 ++
 .../java/org/apache/rave/rest/model/Page.java   |  12 +
 .../apache/rave/rest/model/PageTemplate.java    | 104 ++++++
 .../java/org/apache/rave/rest/model/Widget.java | 204 +++++++++++
 rave-components/rave-core/pom.xml               |   2 +-
 .../portal/model/impl/ApplicationDataImpl.java  |  52 +--
 .../apache/rave/portal/model/impl/PageImpl.java |  23 ++
 .../portal/model/impl/PageTemplateImpl.java     |  10 +
 .../rave/portal/model/impl/WidgetImpl.java      |  10 +
 .../rave/portal/repository/PageRepository.java  |  11 +-
 .../repository/PageTemplateRepository.java      |  21 +-
 .../apache/rave/portal/service/PageService.java |  46 ++-
 .../portal/service/impl/DefaultPageService.java | 162 ++++++---
 .../org/apache/rave/portal/util/PageUtil.java   | 157 +++++++++
 .../rave/portal/util/data/DataImporter.java     | 329 +-----------------
 .../util/data/ModelWrapperDataExecutor.java     | 339 +++++++++++++++++++
 .../rave/rest/impl/DefaultGroupsResource.java   |  47 +++
 .../rest/impl/DefaultOrganizationsResource.java |  50 +++
 .../rave/rest/impl/DefaultPageResource.java     |  75 ++--
 .../rest/impl/DefaultPageTemplatesResource.java |  66 ++++
 .../rave/rest/impl/DefaultWidgetsResource.java  | 104 ++++++
 .../service/impl/DefaultPageServiceTest.java    |  79 ++++-
 .../rave/portal/util/DataImporterTest.java      |   9 +-
 .../impl/DefaultPageTemplatesResourceTest.java  |  86 +++++
 .../rest/impl/DefaultWidgetsResourceTest.java   | 140 ++++++++
 rave-components/rave-jpa/pom.xml                |   2 +-
 .../rave/persistence/jpa/JpaSerializable.java   |  34 ++
 .../rave/portal/model/JpaApplicationData.java   |  48 +--
 .../org/apache/rave/portal/model/JpaPage.java   |  71 +++-
 .../rave/portal/model/JpaPageTemplate.java      |  46 ++-
 .../org/apache/rave/portal/model/JpaWidget.java |  74 ++--
 .../model/conversion/JpaPageConverter.java      |   2 +
 .../conversion/JpaPageTemplateConverter.java    |   1 +
 .../model/conversion/JpaWidgetConverter.java    |   1 +
 .../impl/JpaApplicationDataRepository.java      |  75 ++--
 .../repository/impl/JpaPageRepository.java      | 108 ++++--
 .../impl/JpaPageTemplateRepository.java         |  56 ++-
 .../repository/impl/JpaWidgetRepository.java    |  36 +-
 .../JpaApplicationDataConverterTest.java        |  14 +-
 .../model/conversion/JpaPageConverterTest.java  |   5 +
 .../conversion/JpaWidgetConverterTest.java      |   3 +
 .../impl/JpaApplicationDataRepositoryTest.java  |  52 +--
 .../repository/impl/JpaPageRepositoryTest.java  |  31 ++
 .../impl/JpaPageTemplateRepositoryTest.java     |  27 +-
 .../impl/JpaWidgetRepositoryTest.java           |  73 +++-
 .../rave-jpa/src/test/resources/test_data.sql   |  34 +-
 rave-components/rave-mongodb/pom.xml            |   2 +-
 .../conversion/impl/MongoDbPageConverter.java   |   2 +
 .../impl/MongoDbPageTemplateConverter.java      |   1 +
 .../conversion/impl/MongoDbWidgetConverter.java |   1 +
 .../portal/model/util/MongoDbModelUtil.java     |   2 +
 .../repository/MongoPageTemplateOperations.java |  23 ++
 .../repository/impl/MongoDbPageRepository.java  |  75 +++-
 .../impl/MongoDbPageTemplateRepository.java     |  60 ++--
 .../impl/MongoDbRegionRepository.java           |  37 +-
 .../impl/MongoPageTemplateTemplate.java         |  37 ++
 .../impl/MongoDbPageConverterTest.java          |   2 +
 .../impl/MongoDbWidgetConverterTest.java        |   6 +
 .../impl/MongoDbPageRepositoryTest.java         |  21 ++
 .../impl/MongoDbPageTemplateRepositoryTest.java |  31 +-
 rave-components/rave-web/pom.xml                |   2 +-
 .../portal/web/controller/PageController.java   |   2 +-
 rave-custom-project-archetype/pom.xml           |   2 +-
 rave-demo-gadgets/pom.xml                       |   2 +-
 .../src/main/webapp/actions_contributions.xml   |  91 +++++
 rave-integration-tests/pom.xml                  |  13 +-
 rave-integration-tests/rave-admin-tests/pom.xml |   2 +-
 rave-integration-tests/rave-core-tests/pom.xml  |   2 +-
 .../rave-default-account-tests/pom.xml          |   2 +-
 .../rave-newuser-tests/pom.xml                  |   2 +-
 rave-portal-dependencies/pom.xml                |   2 +-
 rave-portal-resources/pom.xml                   |   2 +-
 .../src/main/resources/db/initial-data.json     |  15 +-
 .../src/main/resources/portal.properties        |   2 +-
 rave-portal-resources/src/main/resources/r.js   |  13 +-
 .../src/main/resources_jpa/dataContext.xml      |   3 +-
 .../src/main/resources_mongo/dataContext.xml    |   3 +-
 .../webapp/WEB-INF/cxf-applicationContext.xml   |   9 +
 .../src/main/webapp/WEB-INF/jsp/views/store.jsp |   1 -
 .../main/webapp/WEB-INF/jsp/views/widget.jsp    |   1 -
 .../WEB-INF/jsp/views/widget.marketplace.jsp    |   1 -
 .../src/main/webapp/WEB-INF/tags/rave_js.tag    |   4 +-
 .../src/main/webapp/static/css/rave-css.less    |   4 +
 .../src/main/webapp/static/script/core/main.js  |   5 +-
 .../static/script/core/rave_action_manager.js   |  62 ++++
 .../static/script/core/rave_opensocial.js       |  86 +++--
 .../webapp/static/script/core/rave_wookie.js    |  78 ++---
 .../webapp/static/script/portal_old/rave_ui.js  |  72 +++-
 .../main/webapp/static/script/requireConfig.js  |   2 +-
 .../src/test/dependencies/osapi.js              |  42 ++-
 .../javascript/core/rave_action_manager.spec    |  26 ++
 rave-portal/pom.xml                             |   2 +-
 .../src/test/resources_jpa/test-dataContext.xml |   3 +-
 .../test/resources_mongo/test-dataContext.xml   |   3 +-
 rave-providers/pom.xml                          |   2 +-
 rave-providers/rave-opensocial-provider/pom.xml |   2 +-
 .../rave-opensocial-client/pom.xml              |   2 +-
 .../config/OpenSocialEnvironment.java           |   2 +-
 .../service/impl/DefaultOpenSocialService.java  |  10 +-
 .../OpenSocialWidgetWrapperRenderer.java        |   7 +-
 .../renderer/OpenSocialWidgetRendererTest.java  |  11 +-
 .../rave-opensocial-core/pom.xml                |   2 +-
 .../impl/DefaultActivityStreamsService.java     |  15 +-
 .../service/impl/DefaultAppDataService.java     |  28 +-
 .../service/impl/DefaultPersonService.java      |   8 +-
 .../opensocial/service/AppDataServiceTest.java  |  54 +--
 .../DefaultActivityStreamsServiceTest.java      |   7 +-
 .../rave-opensocial-server/pom.xml              |   2 +-
 .../rave-shindig-dependencies/pom.xml           |   2 +-
 .../rave-shindig-resources/pom.xml              |   2 +-
 .../src/main/resources/rave.shindig.properties  |  20 +-
 .../classes/containers/default/container.js     |  33 +-
 .../rave-opensocial-server/rave-shindig/pom.xml |   2 +-
 rave-providers/rave-w3c-provider/pom.xml        |   2 +-
 .../web/renderer/W3cRegionWidgetRenderer.java   |  69 ++++
 .../web/renderer/W3cWidgetWrapperRenderer.java  |   7 +-
 132 files changed, 3568 insertions(+), 932 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/rave/blob/5344cc71/pom.xml
----------------------------------------------------------------------
diff --cc pom.xml
index 2fbec76,1df8300..08c05ea
--- a/pom.xml
+++ b/pom.xml
@@@ -32,8 -32,9 +32,9 @@@
      <name>Apache Rave :: rave-project</name>
      <description>Apache Rave Project</description>
      <packaging>pom</packaging>
-     <version>0.23-ANGULAR-SNAPSHOT</version>
 -    <version>0.24-SNAPSHOT</version>
++    <version>0.24-ANGULAR-SNAPSHOT</version>
  
+     <!--TODO: Update with new Git info -->
      <scm>
          <connection>scm:svn:http://svn.apache.org/repos/asf/rave/trunk</connection>
          <developerConnection>scm:svn:https://svn.apache.org/repos/asf/rave/trunk</developerConnection>

http://git-wip-us.apache.org/repos/asf/rave/blob/5344cc71/rave-components/pom.xml
----------------------------------------------------------------------
diff --cc rave-components/pom.xml
index 6a46f9b,ccea0cc..41ac634
--- a/rave-components/pom.xml
+++ b/rave-components/pom.xml
@@@ -24,7 -24,7 +24,7 @@@
      <parent>
          <groupId>org.apache.rave</groupId>
          <artifactId>rave-project</artifactId>
-         <version>0.23-ANGULAR-SNAPSHOT</version>
 -        <version>0.24-SNAPSHOT</version>
++        <version>0.24-ANGULAR-SNAPSHOT</version>
      </parent>
  
      <artifactId>rave-components</artifactId>

http://git-wip-us.apache.org/repos/asf/rave/blob/5344cc71/rave-components/rave-commons/pom.xml
----------------------------------------------------------------------
diff --cc rave-components/rave-commons/pom.xml
index b088519,b30fb2a..8a9eb0e
--- a/rave-components/rave-commons/pom.xml
+++ b/rave-components/rave-commons/pom.xml
@@@ -24,7 -24,7 +24,7 @@@
      <parent>
          <artifactId>rave-components</artifactId>
          <groupId>org.apache.rave</groupId>
-         <version>0.23-ANGULAR-SNAPSHOT</version>
 -        <version>0.24-SNAPSHOT</version>
++        <version>0.24-ANGULAR-SNAPSHOT</version>
      </parent>
  
      <artifactId>rave-commons</artifactId>

http://git-wip-us.apache.org/repos/asf/rave/blob/5344cc71/rave-components/rave-core-api/pom.xml
----------------------------------------------------------------------
diff --cc rave-components/rave-core-api/pom.xml
index 2f67fbc,1c31f6d..d5533e4
--- a/rave-components/rave-core-api/pom.xml
+++ b/rave-components/rave-core-api/pom.xml
@@@ -22,7 -22,7 +22,7 @@@
      <parent>
          <artifactId>rave-components</artifactId>
          <groupId>org.apache.rave</groupId>
-         <version>0.23-ANGULAR-SNAPSHOT</version>
 -        <version>0.24-SNAPSHOT</version>
++        <version>0.24-ANGULAR-SNAPSHOT</version>
      </parent>
      <modelVersion>4.0.0</modelVersion>
  

http://git-wip-us.apache.org/repos/asf/rave/blob/5344cc71/rave-components/rave-core-api/src/main/java/org/apache/rave/rest/PagesResource.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/rave/blob/5344cc71/rave-components/rave-core-api/src/main/java/org/apache/rave/rest/model/Page.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/rave/blob/5344cc71/rave-components/rave-core/pom.xml
----------------------------------------------------------------------
diff --cc rave-components/rave-core/pom.xml
index 51a7738,8bd4f43..1faaeff
--- a/rave-components/rave-core/pom.xml
+++ b/rave-components/rave-core/pom.xml
@@@ -24,7 -24,7 +24,7 @@@
      <parent>
          <artifactId>rave-components</artifactId>
          <groupId>org.apache.rave</groupId>
-         <version>0.23-ANGULAR-SNAPSHOT</version>
 -        <version>0.24-SNAPSHOT</version>
++        <version>0.24-ANGULAR-SNAPSHOT</version>
      </parent>
  
      <artifactId>rave-core</artifactId>

http://git-wip-us.apache.org/repos/asf/rave/blob/5344cc71/rave-components/rave-core/src/main/java/org/apache/rave/rest/impl/DefaultPageResource.java
----------------------------------------------------------------------
diff --cc rave-components/rave-core/src/main/java/org/apache/rave/rest/impl/DefaultPageResource.java
index dc32747,06b0ede..b485a26
--- a/rave-components/rave-core/src/main/java/org/apache/rave/rest/impl/DefaultPageResource.java
+++ b/rave-components/rave-core/src/main/java/org/apache/rave/rest/impl/DefaultPageResource.java
@@@ -20,9 -20,11 +20,12 @@@
  package org.apache.rave.rest.impl;
  
  
+ import com.google.common.collect.Lists;
+ import org.apache.commons.lang3.StringUtils;
+ import org.apache.rave.portal.service.UserService;
  import org.apache.rave.rest.PageUsersResource;
  import org.apache.rave.rest.exception.ResourceNotFoundException;
 +import org.apache.rave.model.PageType;
  import org.apache.rave.portal.service.PageService;
  import org.apache.rave.rest.PagesResource;
  import org.apache.rave.rest.RegionsResource;
@@@ -32,9 -34,9 +35,10 @@@ import org.slf4j.Logger
  import org.slf4j.LoggerFactory;
  
  import javax.inject.Inject;
 +import javax.ws.rs.PathParam;
  import javax.ws.rs.core.Response;
  import java.util.ArrayList;
+ import java.util.Arrays;
  import java.util.List;
  
  public class DefaultPageResource implements PagesResource {
@@@ -73,12 -91,15 +93,15 @@@
  
  
      @Override
-     public Page createPage(Page page) {
-         //TODO: RAVE-977 - when Page type enum is deprecated escape from this logic
-         if (page.getPageType() != null && page.getPageType().equals("user")) {
-             if (page.getName() == null) {
-                 throw new BadRequestException("Page name property must be defined.");
-             }
+     public Page createPage(String pageTemplateId, Page page) {
+         if (page.getName() == null) {
+             throw new BadRequestException("Page name property must be defined.");
+         }
+         org.apache.rave.model.Page fromDb;
+         if(StringUtils.isNotBlank(pageTemplateId)) {
+             fromDb = pageService.addNewPage(page.getName(), null, pageTemplateId);
 -        //TODO: RAVE-977 - when Page type enum is deprecated escape from this logic
++            //TODO: RAVE-977 - when Page type enum is deprecated escape from this logic
+         } else if (page.getPageType().equals("user")) {
              if (page.getPageLayoutCode() == null) {
                  throw new BadRequestException("Page pageLayoutCode property must be defined.");
              }

http://git-wip-us.apache.org/repos/asf/rave/blob/5344cc71/rave-components/rave-jpa/pom.xml
----------------------------------------------------------------------
diff --cc rave-components/rave-jpa/pom.xml
index 943c811,7a7c14c..387c3bc
--- a/rave-components/rave-jpa/pom.xml
+++ b/rave-components/rave-jpa/pom.xml
@@@ -24,7 -24,7 +24,7 @@@
      <parent>
          <artifactId>rave-components</artifactId>
          <groupId>org.apache.rave</groupId>
-         <version>0.23-ANGULAR-SNAPSHOT</version>
 -        <version>0.24-SNAPSHOT</version>
++        <version>0.24-ANGULAR-SNAPSHOT</version>
      </parent>
  
      <artifactId>rave-jpa</artifactId>

http://git-wip-us.apache.org/repos/asf/rave/blob/5344cc71/rave-components/rave-mongodb/pom.xml
----------------------------------------------------------------------
diff --cc rave-components/rave-mongodb/pom.xml
index 2b23f56,9310a63..2808fbb
--- a/rave-components/rave-mongodb/pom.xml
+++ b/rave-components/rave-mongodb/pom.xml
@@@ -22,7 -22,7 +22,7 @@@
      <parent>
          <artifactId>rave-components</artifactId>
          <groupId>org.apache.rave</groupId>
-         <version>0.23-ANGULAR-SNAPSHOT</version>
 -        <version>0.24-SNAPSHOT</version>
++        <version>0.24-ANGULAR-SNAPSHOT</version>
      </parent>
      <modelVersion>4.0.0</modelVersion>
  

http://git-wip-us.apache.org/repos/asf/rave/blob/5344cc71/rave-components/rave-web/pom.xml
----------------------------------------------------------------------
diff --cc rave-components/rave-web/pom.xml
index 0ecd940,b79b28f..b9517e9
--- a/rave-components/rave-web/pom.xml
+++ b/rave-components/rave-web/pom.xml
@@@ -26,7 -26,7 +26,7 @@@
      <parent>
          <artifactId>rave-components</artifactId>
          <groupId>org.apache.rave</groupId>
-         <version>0.23-ANGULAR-SNAPSHOT</version>
 -        <version>0.24-SNAPSHOT</version>
++        <version>0.24-ANGULAR-SNAPSHOT</version>
      </parent>
  
      <artifactId>rave-web</artifactId>

http://git-wip-us.apache.org/repos/asf/rave/blob/5344cc71/rave-custom-project-archetype/pom.xml
----------------------------------------------------------------------
diff --cc rave-custom-project-archetype/pom.xml
index 2ebb844,769f778..dfa643c
--- a/rave-custom-project-archetype/pom.xml
+++ b/rave-custom-project-archetype/pom.xml
@@@ -23,7 -23,7 +23,7 @@@
      <parent>
          <groupId>org.apache.rave</groupId>
          <artifactId>rave-project</artifactId>
-         <version>0.23-ANGULAR-SNAPSHOT</version>
 -        <version>0.24-SNAPSHOT</version>
++        <version>0.24-ANGULAR-SNAPSHOT</version>
      </parent>
  
      <artifactId>rave-custom-project-archetype</artifactId>

http://git-wip-us.apache.org/repos/asf/rave/blob/5344cc71/rave-demo-gadgets/pom.xml
----------------------------------------------------------------------
diff --cc rave-demo-gadgets/pom.xml
index 285befb,b7981fb..6d0b81d
--- a/rave-demo-gadgets/pom.xml
+++ b/rave-demo-gadgets/pom.xml
@@@ -25,7 -25,7 +25,7 @@@
  	<parent>
  		<groupId>org.apache.rave</groupId>
  		<artifactId>rave-project</artifactId>
- 		<version>0.23-ANGULAR-SNAPSHOT</version>
 -		<version>0.24-SNAPSHOT</version>
++		<version>0.24-ANGULAR-SNAPSHOT</version>
  	</parent>
  
  	<artifactId>rave-demo-gadgets</artifactId>

http://git-wip-us.apache.org/repos/asf/rave/blob/5344cc71/rave-integration-tests/pom.xml
----------------------------------------------------------------------
diff --cc rave-integration-tests/pom.xml
index d3cc7ce,2552328..6edb839
--- a/rave-integration-tests/pom.xml
+++ b/rave-integration-tests/pom.xml
@@@ -24,7 -24,7 +24,7 @@@
      <parent>
          <groupId>org.apache.rave</groupId>
          <artifactId>rave-project</artifactId>
-         <version>0.23-ANGULAR-SNAPSHOT</version>
 -        <version>0.24-SNAPSHOT</version>
++        <version>0.24-ANGULAR-SNAPSHOT</version>
          <relativePath>../pom.xml</relativePath>
      </parent>
  

http://git-wip-us.apache.org/repos/asf/rave/blob/5344cc71/rave-integration-tests/rave-admin-tests/pom.xml
----------------------------------------------------------------------
diff --cc rave-integration-tests/rave-admin-tests/pom.xml
index adefed9,97cb10d..017f31f
--- a/rave-integration-tests/rave-admin-tests/pom.xml
+++ b/rave-integration-tests/rave-admin-tests/pom.xml
@@@ -28,7 -28,7 +28,7 @@@
      <parent>
          <groupId>org.apache.rave.integration-tests</groupId>
          <artifactId>rave-integration-tests</artifactId>
-         <version>0.23-ANGULAR-SNAPSHOT</version>
 -        <version>0.24-SNAPSHOT</version>
++        <version>0.24-ANGULAR-SNAPSHOT</version>
          <relativePath>../pom.xml</relativePath>
      </parent>
  

http://git-wip-us.apache.org/repos/asf/rave/blob/5344cc71/rave-integration-tests/rave-core-tests/pom.xml
----------------------------------------------------------------------
diff --cc rave-integration-tests/rave-core-tests/pom.xml
index 89eac3b,70fa390..34218e4
--- a/rave-integration-tests/rave-core-tests/pom.xml
+++ b/rave-integration-tests/rave-core-tests/pom.xml
@@@ -28,7 -28,7 +28,7 @@@
    <parent>
      <groupId>org.apache.rave.integration-tests</groupId>
      <artifactId>rave-integration-tests</artifactId>
-     <version>0.23-ANGULAR-SNAPSHOT</version>
 -    <version>0.24-SNAPSHOT</version>
++    <version>0.24-ANGULAR-SNAPSHOT</version>
      <relativePath>../pom.xml</relativePath>
    </parent>
  

http://git-wip-us.apache.org/repos/asf/rave/blob/5344cc71/rave-integration-tests/rave-default-account-tests/pom.xml
----------------------------------------------------------------------
diff --cc rave-integration-tests/rave-default-account-tests/pom.xml
index bcae601,f99b535..5572924
--- a/rave-integration-tests/rave-default-account-tests/pom.xml
+++ b/rave-integration-tests/rave-default-account-tests/pom.xml
@@@ -28,7 -28,7 +28,7 @@@
      <parent>
          <groupId>org.apache.rave.integration-tests</groupId>
          <artifactId>rave-integration-tests</artifactId>
-         <version>0.23-ANGULAR-SNAPSHOT</version>
 -        <version>0.24-SNAPSHOT</version>
++        <version>0.24-ANGULAR-SNAPSHOT</version>
          <relativePath>../pom.xml</relativePath>
      </parent>
  

http://git-wip-us.apache.org/repos/asf/rave/blob/5344cc71/rave-integration-tests/rave-newuser-tests/pom.xml
----------------------------------------------------------------------
diff --cc rave-integration-tests/rave-newuser-tests/pom.xml
index d62f834,842c0e2..95725d2
--- a/rave-integration-tests/rave-newuser-tests/pom.xml
+++ b/rave-integration-tests/rave-newuser-tests/pom.xml
@@@ -28,7 -28,7 +28,7 @@@
      <parent>
          <groupId>org.apache.rave.integration-tests</groupId>
          <artifactId>rave-integration-tests</artifactId>
-         <version>0.23-ANGULAR-SNAPSHOT</version>
 -        <version>0.24-SNAPSHOT</version>
++        <version>0.24-ANGULAR-SNAPSHOT</version>
          <relativePath>../pom.xml</relativePath>
      </parent>
  

http://git-wip-us.apache.org/repos/asf/rave/blob/5344cc71/rave-portal-dependencies/pom.xml
----------------------------------------------------------------------
diff --cc rave-portal-dependencies/pom.xml
index b2b6aba,54a3afc..3935023
--- a/rave-portal-dependencies/pom.xml
+++ b/rave-portal-dependencies/pom.xml
@@@ -26,7 -26,7 +26,7 @@@
      <parent>
          <artifactId>rave-project</artifactId>
          <groupId>org.apache.rave</groupId>
-         <version>0.23-ANGULAR-SNAPSHOT</version>
 -        <version>0.24-SNAPSHOT</version>
++        <version>0.24-ANGULAR-SNAPSHOT</version>
      </parent>
  
      <artifactId>rave-portal-dependencies</artifactId>

http://git-wip-us.apache.org/repos/asf/rave/blob/5344cc71/rave-portal-resources/pom.xml
----------------------------------------------------------------------
diff --cc rave-portal-resources/pom.xml
index ddf8d04,65a1ad0..73bbc15
--- a/rave-portal-resources/pom.xml
+++ b/rave-portal-resources/pom.xml
@@@ -24,7 -24,7 +24,7 @@@
      <parent>
          <artifactId>rave-project</artifactId>
          <groupId>org.apache.rave</groupId>
-         <version>0.23-ANGULAR-SNAPSHOT</version>
 -        <version>0.24-SNAPSHOT</version>
++        <version>0.24-ANGULAR-SNAPSHOT</version>
      </parent>
  
      <artifactId>rave-portal-resources</artifactId>

http://git-wip-us.apache.org/repos/asf/rave/blob/5344cc71/rave-portal-resources/src/main/webapp/static/css/rave-css.less
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/rave/blob/5344cc71/rave-portal-resources/src/main/webapp/static/script/core/rave_opensocial.js
----------------------------------------------------------------------
diff --cc rave-portal-resources/src/main/webapp/static/script/core/rave_opensocial.js
index d3cff4d,7dea976..3aeb187
--- a/rave-portal-resources/src/main/webapp/static/script/core/rave_opensocial.js
+++ b/rave-portal-resources/src/main/webapp/static/script/core/rave_opensocial.js
@@@ -113,13 -116,38 +116,38 @@@ define(['underscore', 'core/rave_view_m
              };
          }
  
+         function implementActions() {
+             if(!container.actions) {
+                 log("Could not initialize actions as the feature is not enabled in the Shindig common container.  Check the rave properties file.");
+                 return;
+             }
+             container.actions.registerShowActionsHandler(function(actions) {
+                 _.each(actions, function(action){
+                     //TODO: There is a bug in the shindig code where the action is assumed to launch a new gadget.  This works around the issue
+                     actionManager.createAction(action.id, action.label, action.path.replace("gadget", "widget"), action.moduleId, action.icon, action.tooltip, function() {
+                         var site = container._siteByWidgetId[action.moduleId];
+                         var holder = site.getActiveSiteHolder();
+                         if (holder) {
+                             gadgets.rpc.call(holder.getIframeId(), 'actions.runAction', null, action.id, null);
+                         }
+                     })
+                 })
+             });
+ 
+             container.actions.registerHideActionsHandler(function (actions){
+                 _.each(actions, function(action){
+                     actionManager.removeAction(action.id);
+                 })
+             });
+         }
+ 
          function requestNavigateTo(args, viewName, opt_params, opt_ownerId) {
              var widget = args.gs._widget,
 -                viewSurface = viewName.split('.')[0],
 -                renderInto = viewManager.getView(viewSurface) ? viewSurface : widget._el;
 -            //If the element has no ID then it was launched in some secondary location.  Destroy the view.
 -            if(widget._el.id === "") viewManager.destroyView(widget._view);
 -            widget.render(renderInto, {view: viewName, view_params: opt_params, ownerId: opt_ownerId});
 +                viewSurface = viewName || stateManager.getDefaultView();
 +
 +            viewSurface = viewSurface.split('.')[0];
 +
 +            widget.navigate(viewSurface, {view: viewName, view_params: opt_params, ownerId: opt_ownerId});
          }
  
          function setPref(args, editToken, prefName, prefValue) {
@@@ -193,28 -221,24 +221,31 @@@
                  return;
              }
              opts = opts || {};
-             if (!widget._site) {
-                 widget._site = container.newGadgetSite(widget._el);
-                 widget._site._widget = widget;
-             }
 -            var site = container.newGadgetSite(el);
 -            site._widget = widget;
 -            site.moduleId_ = widget.regionWidgetId;
 -            widget._site = site;
 -            container._siteByWidgetId[widget.regionWidgetId] = site;
++			if (!widget._site) {
++				widget._site = container.newGadgetSite(el);
++				widget._site.moduleId_ = widget.regionWidgetId;
++				widget._site._widget = widget;
++			}
++			container._siteByWidgetId[widget.regionWidgetId] = widget._site;
  
              var renderParams = {};
-             renderParams[osapi.container.RenderParam.VIEW] = opts.view || widget.constructor.defaultView;
 -            renderParams[osapi.container.RenderParam.VIEW] = opts.view || stateManager.getDefaultView();
++            renderParams[osapi.container.RenderParam.VIEW] = opts.view || widget.constructor.defaultView || stateManager.getDefaultView();
              renderParams[osapi.container.RenderParam.ALLOW_DEFAULT_VIEW ] = opts.allowDefaultView;
-             renderParams[osapi.container.RenderParam.DEBUG ] = opts.debug;
-             renderParams[osapi.container.RenderParam.HEIGHT ] = opts.height || widget.constructor.defaultHeight;
-             renderParams[osapi.container.RenderParam.NO_CACHE ] = opts.noCache;
-             renderParams[osapi.container.RenderParam.TEST_MODE] = opts.testMode;
-             renderParams[osapi.container.RenderParam.WIDTH ] = opts.width || widget.constructor.defaultWidth;
+             renderParams[osapi.container.RenderParam.DEBUG ] = opts.debug || stateManager.getDebugMode();
+             renderParams[osapi.container.RenderParam.HEIGHT ] = getHeightFromParams(opts);
+             renderParams[osapi.container.RenderParam.NO_CACHE ] = opts.noCache || stateManager.getDebugMode();
+             renderParams[osapi.container.RenderParam.TEST_MODE] = opts.testMode || stateManager.getDebugMode();
+             renderParams[osapi.container.RenderParam.WIDTH ] = getWidthFromParams(opts);
              renderParams[osapi.container.RenderParam.USER_PREFS] = getCompleteUserPrefSet(widget.userPrefs, widget.metadata.userPrefs);
-             container.navigateGadget(widget._site, widget.widgetUrl, opts.view_params, renderParams, opts.callback);
-         }
- 
-         exports.unrenderWidget = function (widget) {
-             if (widget._site) {
-                 container.closeGadget(widget._site);
-             }
-         }
+             renderParams[osapi.container.RenderParam.MODULE_ID] = widget.regionWidgetId;
+             container.navigateGadget(site, widget.widgetUrl, opts.view_params, renderParams, opts.callback);
 -        }
++        };
++		
++		exports.unrenderWidget = function (widget) {
++			if (widget._site) {
++				container.closeGadget(widget._site);
++			}
++		}
  
          /**
           * Combines the default user pref list from the metadata with those set by the user

http://git-wip-us.apache.org/repos/asf/rave/blob/5344cc71/rave-portal-resources/src/main/webapp/static/script/core/rave_wookie.js
----------------------------------------------------------------------
diff --cc rave-portal-resources/src/main/webapp/static/script/core/rave_wookie.js
index 8e3153a,4f3dc0b..db6bfe9
--- a/rave-portal-resources/src/main/webapp/static/script/core/rave_wookie.js
+++ b/rave-portal-resources/src/main/webapp/static/script/core/rave_wookie.js
@@@ -23,54 -23,44 +23,46 @@@
   * @requires rave_openajax_hub
   * @requires rave_state_manager
   */
- define(['core/rave_openajax_hub', 'core/rave_state_manager'], function (managedHub, stateManager) {
-     var exports = {}
+ define(['core/rave_openajax_hub', 'core/rave_state_manager'], function(managedHub, stateManager){
+         var exports = {}
  
-     exports.initWidget = function (widget) {
-     }
-     exports.renderWidget = function (widget, opts) {
-         var widgetBodyElement = document.getElementById(["widget-", widget.regionWidgetId, "-body"].join(""));
-         window["onWidget" + widget.regionWidgetId + "Load"] = function () {
-             window.document.getElementById(widget.regionWidgetId).style.visibility = "visible";
-         };
+         exports.initWidget = function(widget){}
+         exports.renderWidget = function(widget, el, opts){
+             var widgetBodyElement = document.getElementById(["widget-", widget.regionWidgetId, "-body"].join(""));
+             window["onWidget"+widget.regionWidgetId+"Load"] = function(){
+                 window.document.getElementById(widget.regionWidgetId).style.visibility="visible";
+             };
  
-         new OpenAjax.hub.IframeContainer(managedHub, "" + widget.regionWidgetId,
-             {
-                 Container: {
-                     onSecurityAlert: onClientSecurityAlert,
-                     onConnect: onClientConnect,
-                     onDisconnect: onClientDisconnect
-                 },
-                 IframeContainer: {
-                     parent: widget._el,
-                     iframeAttrs: {
-                         height: widget.height || stateManager.getDefaultHeight(),
-                         width: widget.width || stateManager.getDefaultWidth(),
-                         frameborder: 0
+             new OpenAjax.hub.IframeContainer(managedHub , ""+widget.regionWidgetId,
+                 {
+                     Container: {
+                         onSecurityAlert: onClientSecurityAlert,
+                         onConnect:       onClientConnect,
+                         onDisconnect:    onClientDisconnect
                      },
-                     uri: widget.widgetUrl,
-                     onGadgetLoad: "onWidget" + widget.regionWidgetId + "Load"
+                     IframeContainer: {
+                         parent:      el,
+                         iframeAttrs: {
+                             height: widget.height || stateManager.getDefaultHeight(),
+                             width:  widget.width || stateManager.getDefaultWidth(),
+                             frameborder: 0
+                         },
+                         uri: widget.widgetUrl,
+                         onGadgetLoad: function(){window["onWidget"+widget.regionWidgetId+"Load"].call()}
+                     }
                  }
-             }
-         );
-     }
+             );
 -        }
++        };    
++	
++	    exports.unrenderWidget = function () { /*TODO...*/ }
  
-     exports.unrenderWidget = function () {
-         //TODO...
-     }
+         function onClientSecurityAlert(source, alertType) {  /* Handle client-side security alerts */  }
+         function onClientConnect(container) {        /* Called when client connects */   }
+         function onClientDisconnect(container) {     /* Called when client disconnects */ }
  
-     function onClientSecurityAlert(source, alertType) {  /* Handle client-side security alerts */
-     }
+         exports.closeWidget = function(widget){
+             //TODO...
+         }
  
-     function onClientConnect(container) {        /* Called when client connects */
-     }
- 
-     function onClientDisconnect(container) {     /* Called when client disconnects */
-     }
- 
-     exports.closeWidget = function (widget) {
-         //TODO...
-     }
- 
-     return exports;
+         return exports;
  })

http://git-wip-us.apache.org/repos/asf/rave/blob/5344cc71/rave-portal-resources/src/main/webapp/static/script/portal_old/rave_ui.js
----------------------------------------------------------------------
diff --cc rave-portal-resources/src/main/webapp/static/script/portal_old/rave_ui.js
index b0dd166,0000000..a0d5fca
mode 100644,000000..100644
--- a/rave-portal-resources/src/main/webapp/static/script/portal_old/rave_ui.js
+++ b/rave-portal-resources/src/main/webapp/static/script/portal_old/rave_ui.js
@@@ -1,942 -1,0 +1,996 @@@
 +/*
 + * Licensed to the Apache Software Foundation (ASF) under one
 + * or more contributor license agreements.  See the NOTICE file
 + * distributed with this work for additional information
 + * regarding copyright ownership.  The ASF licenses this file
 + * to you under the Apache License, Version 2.0 (the
 + * "License"); you may not use this file except in compliance
 + * with the License.  You may obtain a copy of the License at
 + *
 + *   http://www.apache.org/licenses/LICENSE-2.0
 + *
 + * Unless required by applicable law or agreed to in writing,
 + * software distributed under the License is distributed on an
 + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 + * KIND, either express or implied.  See the License for the
 + * specific language governing permissions and limitations
 + * under the License.
 + */
 +
 +define(["jquery", "underscore", "rave",
 +    "portal_old/rave_portal", "portal_old/rave_backbone", "portal_old/rave_models", "portal_old/rave_templates",
 +    "jqueryUi"],
 +    function ($, _, rave, ravePortal, raveBackbone, raveModels, raveTemplates) {
 +        var exports = {};
 +
 +        /*
 +         Build rave client side views
 +         */
 +        var views = exports.views = {};
 +
 +        var App = raveBackbone.View.extend({
 +            models: {
 +                page: raveModels.currentPage
 +            },
 +
 +            initialize: function () {
 +                this.models.page.on('acceptShare', ravePortal.viewPage);
 +                this.models.page.on('declineShare', function () {
 +                    document.location.href = rave.getContext();
 +                });
 +            }
 +        });
 +
 +        views.app = new App();
 +
 +
 +        function initializePageSharing() {
 +            /*
 +             View for managing sharing / cloning of pages
 +             */
 +            var PageSharingModalView = raveBackbone.View.extend({
 +                template: raveTemplates.templates['user-search-view'],
 +                //the bootstrap modal div
 +                modalDiv: $('#sharePageDialog'),
 +                //attach point for this view
 +                container: $('#sharePageDialogContent'),
 +
 +                models: {
 +                    page: raveModels.currentPage,
 +                    users: raveModels.users
 +                },
 +
 +                initialize: function () {
 +                    var page = this.models.page;
 +                    var users = this.models.users;
 +
 +                    this.constructor.__super__.initialize.apply(this);
 +
 +                    page.on('share', this.flash, this);
 +                    page.on('error', this.handleError, this);
 +
 +                    //whenever the modal is displayed reset the view
 +                    this.modalDiv.on('show', function () {
 +                        users.fetchPage(1);
 +                    });
 +
 +                    //extend users toViewModel function to include share properties
 +                    this.models.users.toViewModel = _.wrap(this.models.users.toViewModel, function (toViewModel) {
 +                        var model = toViewModel.apply(this);
 +
 +                        _.each(model.users, function (user) {
 +                            user.isOwner = page.isUserOwner(user.id);
 +                            user.hasShare = page.isUserMember(user.id);
 +                            user.hasEdit = page.isUserEditor(user.id);
 +                        });
 +
 +                        return model;
 +                    });
 +
 +                    this.container.html(this.$el);
 +                },
 +
 +                events: {
 +                    'click #shareSearchButton': 'search',
 +                    'keypress #searchTerm': 'search',
 +                    'click #clearSearchButton': 'clearSearch',
 +                    'click #pagingul a': 'page',
 +                    'click .searchResultRecord a': 'shareAction'
 +                },
 +
 +                search: function (e) {
 +                    //allow search function to trigger from enter keypress or button click
 +                    if (e.which == 13 || _.isUndefined(e.which)) {
 +                        var term = $('#searchTerm', this.$el).val();
 +
 +                        this.models.users.filter(term);
 +                    }
 +                },
 +
 +                clearSearch: function (e) {
 +                    this.models.users.filter(null);
 +                },
 +
 +                page: function (e) {
 +                    var page = $(e.target).data('pagenumber');
 +
 +                    this.models.users.fetchPage(page);
 +                },
 +
 +                //manages any add / remove share, editor or clone actions
 +                shareAction: function (e) {
 +                    var userId = $(e.target).data('userid');
 +                    var action = $(e.target).data('action');
 +
 +                    this.models.page[action](userId);
 +                },
 +
 +                //flash success messages
 +                flash: function (event, userId) {
 +                    var eventsToMessages = {
 +                        'member:add': 'create.share',
 +                        'member:remove': 'revoke.share',
 +                        'editor:add': '',
 +                        'editor:remove': '',
 +                        'clone': 'success.clone.page'
 +                    }
 +
 +                    var msg = eventsToMessages[event];
 +
 +                    if (msg) {
 +                        var message = ravePortal.getClientMessage(msg);
 +                        var user = this.models.users.get(userId);
 +                        ravePortal.showInfoMessage('(' + user.get('username') + ') ' + message);
 +                    }
 +                },
 +
 +                //TODO: deal with errors better. Until we have a better api or there is another view for this modal,
 +                //manually manage the form
 +                handleError: function (errorCode, userId) {
 +                    var self = this;
 +
 +                    if (errorCode == 'DUPLICATE_ITEM') {
 +                        this.modalDiv.modal('hide');
 +                        $("#pageMenuDialogHeader").html(ravePortal.getClientMessage("page.update"));
 +                        $("#pageFormErrors").html(ravePortal.getClientMessage("page.duplicate_name"));
 +                        $("#pageLayoutGroup").hide();
 +                        var $pageMenuUpdateButton = $("#pageMenuUpdateButton");
 +                        $pageMenuUpdateButton.html(ravePortal.getClientMessage("common.save"));
 +                        // unbind the previous click event since we are sharing the
 +                        // dialog between separate add/edit page actions
 +                        $pageMenuUpdateButton.unbind('click');
 +                        $pageMenuUpdateButton.click(function () {
 +                            var $pageForm = $("#pageForm");
 +                            var $tab_title_input = $("#tab_title");
 +                            if ($pageForm.valid()) {
 +                                self.models.page.cloneForUser(userId, $tab_title_input.val());
 +                                $("#pageMenuDialog").modal('hide');
 +                            }
 +                        });
 +                        $('#pageMenuDialog').on('shown', function () {
 +                            $("#tab_title").first().focus();
 +                        });
 +                        //
 +                        $("#pageMenuDialog").modal('show');
 +                    } else {
 +                        $("#pageMenuDialog").modal('hide');
 +                        alert(ravePortal.getClientMessage("api.rpc.error.internal"));
 +                    }
 +                }
 +            });
 +            views.pageSharingModal = new PageSharingModalView();
 +        }
 +
 +        function displayEmptyPageMessage() {
 +            $("#emptyPageMessageWrapper").removeClass("hidden");
 +        }
 +
 +        exports.displayEmptyPageMessage = displayEmptyPageMessage;
 +
 +        function showEmptyDisplay() {
 +            if (_.isEmpty(rave.getWidgets())) {
 +                displayEmptyPageMessage();
 +            }
 +        }
 +
 +        function getNonLockedRegions() {
 +            return $(".region:not(.region-locked)");
 +        }
 +
 +        function setupDragAndDrop() {
 +            var uiState = {
 +                widget: null,
 +                currentRegion: null,
 +                targetRegion: null,
 +                targetIndex: null
 +            };
 +
 +            getNonLockedRegions().sortable({
 +                connectWith: '.region', // defines which regions are dnd-able
 +                scroll: true, // whether to scroll the window if the user goes outside the areas
 +                opacity: 0.5, // the opacity of the object being dragged
 +                revert: true, // smooth snap animation
 +                cursor: 'move', // the cursor to show while dnd
 +                handle: '.widget-title-bar-draggable', // the draggable handle
 +                forcePlaceholderSize: true, // size the placeholder to the size of the widget
 +                tolerance: 'pointer', // change dnd drop zone on mouse-over
 +                start: dragStart, // event listener for drag start
 +                stop: dragStop, // event listener for drag stop
 +                over: dragOver // event listener for drag over
 +            });
 +
 +            function dragStart(event, ui) {
 +                adjustRowRegionsHeights();
 +                var $regions = getNonLockedRegions();
 +                // highlight the draggable regions
 +                $regions.addClass("regionDragging");
 +                // remove invisible border so nothing moves
 +                $regions.removeClass("regionNonDragging");
 +
 +                var widgetEl = ui.item.children(".widget").get(0);
 +                uiState.widget = rave.getWidget(ravePortal.getObjectIdFromDomId(widgetEl.id));
 +                uiState.currentRegion = ravePortal.getObjectIdFromDomId(ui.item.parent().get(0).id);
 +
++                // Workaround for SHINDIG-1965 to keep the iframe re-parenting from firing the load events again
++                $(widgetEl).find('iframe').removeAttr('onload');
++
 +                //for every drag operation, create an overlay for each iframe
 +                //to prevent the iframe from intercepting mouse events
 +                //which kills drag performance
 +                $(".widget").each(function (index, element) {
 +                    addOverlay($(element));
 +                });
 +            }
 +
 +            function dragStop(event, ui) {
 +                var $regions = getNonLockedRegions();
 +
 +                // reset padding to 0 after drag on all rows
 +                if ($(".widgetRow").length) {
 +                    var rows = $regions.find(".widgetRow");
 +                    rows.each(resetRowsRegionsHeight);
 +                }
 +
 +                // remove the draggable regions visible border
 +                $regions.removeClass("regionDragging");
 +                // add an invisible border so nothing moves
 +                $regions.addClass("regionNonDragging");
 +
 +                $(".dnd-overlay").remove();
 +                //Fixes a bug where the jQuery style attribute remains set in chrome
 +                ui.item.attr("style", "");
 +                uiState.targetRegion = ravePortal.getObjectIdFromDomId(ui.item.parent().get(0).id);
 +                uiState.targetIndex = ui.item.index();
 +
 +                uiState.widget.moveToRegion(uiState.currentRegion, uiState.targetRegion, uiState.targetIndex);
 +
 +                clearState();
 +            }
 +
 +            function clearState() {
 +                uiState.currentRegion = null;
 +                uiState.targetRegion = null;
 +                uiState.targetIndex = null;
 +                uiState.widget = null;
 +            }
 +
 +            function dragOver(event, ui) {
 +                adjustRowRegionsHeights();
 +            }
 +
 +            // dynamically adjust heights of all regions
 +            function adjustRowRegionsHeights() {
 +                // handle region areas for upper rows
 +                if ($(".upperRow").length) {
 +                    var rows = $(".regions").find(".upperRow");
 +                    rows.each(adjustUpperRowRegionsHeight);
 +                }
 +
 +                // handle region areas for the bottom row
 +                if ($(".bottomRow").length) {
 +                    var row = $(".regions").find(".bottomRow");
 +                    adjustBottomRowRegionsHeight(row)
 +                }
 +            }
 +
 +            // adjusts the padding-bottom value of all regions in bottom row to either fill the empty space or
 +            // act as an upper row
 +            function adjustBottomRowRegionsHeight(row) {
 +                resetRowsRegionsHeight(row);
 +                var bodyHeight = $('body').outerHeight();
 +                var windowHeight = $(window).height();
 +                // Instances where no scroll bar currently exists
 +                if (windowHeight >= bodyHeight) {
 +                    var pageHeight = $("#pageContent").outerHeight();
 +                    var headerHeight = bodyHeight - pageHeight;
 +                    var upperRegionsMaxHeights = 0;
 +                    if ($(".upperRow").length) {
 +                        var rows = $(".regions").find(".upperRow");
 +                        for (var x = 0; x < rows.length; x++) {
 +                            var rowMaxHeight = getRowRegionsMaxHeight(rows.get(x));
 +                            upperRegionsMaxHeights = upperRegionsMaxHeights + rowMaxHeight;
 +                        }
 +                    }
 +                    // determine maximum size possible for bottom region
 +                    // 50 px of buffer also removed to prevent scroll-bar from appearing in any cases
 +                    var bottomPadding = (windowHeight - 50) - (upperRegionsMaxHeights + headerHeight);
 +
 +                    setRowsRegionsHeight(row, bottomPadding);
 +                }
 +                // Instances where scroll bar currently exists, can default to upper row behavior
 +                else {
 +                    adjustUpperRowRegionsHeight(row);
 +                }
 +                // refresh sortables cached positions
 +                getNonLockedRegions().sortable("refreshPositions");
 +            }
 +
 +
 +            // adjusts the padding-bottom value of all regions in upper rows to match the value of the
 +            // tallest region in the row
 +            function adjustUpperRowRegionsHeight(row) {
 +                // when called by each, first argument is a number instead of a row value
 +                var row = (typeof row === 'number') ? $(this) : row;
 +
 +                resetRowsRegionsHeight(row);
 +
 +                // sets total region height to the height of tallest region
 +                setRowsRegionsHeight(row, getRowRegionsMaxHeight(row));
 +
 +                // refresh sortables cached positions
 +                getNonLockedRegions().sortable("refreshPositions");
 +            }
 +
 +            // Returns the height of the tallest region in row, minimum 100 px
 +            function getRowRegionsMaxHeight(row) {
 +                var rowChildren = $(row).children();
 +                var maxHeight = 100;
 +                for (var x = 0; x < rowChildren.length; x++) {
 +                    if ($(rowChildren.get(x)).outerHeight() > maxHeight) {
 +                        maxHeight = $(rowChildren.get(x)).outerHeight();
 +                    }
 +                }
 +                return maxHeight;
 +            }
 +
 +            // Restores the padding-bottom value to the original for all regions in given row
 +            function resetRowsRegionsHeight(row) {
 +                // when called by each, first argument is a number instead of a row value
 +                var row = (typeof row === 'number') ? $(this) : row;
 +
 +                var rowChildren = $(row).children();
 +                for (var x = 0; x < rowChildren.length; x++) {
 +                    // reset to 5, the initial value before dragging
 +                    $(rowChildren.get(x)).css("padding-bottom", 5);
 +                }
 +            }
 +
 +            // Sets the padding-bottom value, so that the total height is the given value for all regions in given row
 +            function setRowsRegionsHeight(row, maxHeight) {
 +                var rowChildren = $(row).children();
 +                for (var x = 0; x < rowChildren.length; x++) {
 +                    if ($(rowChildren.get(x)).outerHeight() != maxHeight) {
 +                        var defaultPadding = parseInt($(rowChildren.get(x)).css("padding-bottom").replace("px", ""));
 +                        $(rowChildren.get(x)).css("padding-bottom", (defaultPadding + maxHeight - $(rowChildren.get(x)).outerHeight()));
 +                    }
 +                }
 +            }
 +
 +            function addOverlay(jqElm) {
 +                var overlay = $('<div></div>');
 +                var styleMap = {
 +                    position: "absolute",
 +                    height: jqElm.height(),
 +                    width: jqElm.width(),
 +                    'z-index': 10,
 +                    opacity: 0.7,
 +                    background: "#FFFFFF"
 +                };
 +
 +                // style it and give it the marker class
 +                $(overlay).css(styleMap);
 +                $(overlay).addClass("dnd-overlay");
 +                // add it to the dom before the iframe so it covers it
 +                jqElm.prepend(overlay[0]);
 +            }
 +        }
 +
 +        function showWidgetPrefs(widget) {
 +            var WIDGET_PREFS_INPUT_REQUIRED_CLASS = "widget-prefs-input-required";
 +            var WIDGET_PREFS_INPUT_FAILED_VALIDATION = "widget-prefs-input-failed-validation";
 +
 +            var PIPE_REGEX = /\|/g;
 +
 +            function WIDGET_PREFS_CONTENT(regionWidgetId) {
 +                return "widget-" + regionWidgetId + "-prefs-content";
 +            }
 +
 +            var widgetDefinition = widget;
 +            var userPrefs = widgetDefinition.metadata.userPrefs;
 +            var hasRequiredUserPrefs = false;
 +
 +            if (widgetDefinition.metadata.views.preferences) {
 +                var opts = {};
 +                _.extend(opts, widgetDefinition.metadata.views.preferences, {view: 'preferences'});
 +                widget.render('dialog', opts);
 +            } else {
 +                //format the data for display
 +                _.each(userPrefs, function (pref) {
 +                    //find current value of each pref
 +                    pref.value = widgetDefinition.userPrefs[pref.name] || pref.defaultValue;
 +
 +                    if (pref.required) {
 +                        hasRequiredUserPrefs = true;
 +                    }
 +
 +                    //for ENUM preferences find which option should be selected
 +                    if (pref.dataType == 'ENUM') {
 +                        var selectedPref = _.find(pref.orderedEnumValues, function (option) {
 +                            return option.value == pref.value;
 +                        });
 +                        selectedPref.selected = true;
 +                    }
 +                    if (pref.dataType == 'LIST') {
 +                        pref.value = pref.value.replace(PIPE_REGEX, "\n");
 +                    }
 +
 +                    //if pref.dataType = "LIST", add a flag pref.LIST to #if against in the template
 +                    pref[pref.dataType] = true;
 +
 +                });
 +
 +                var markup = raveTemplates.templates['widget-preferences']({
 +                    userPrefs: userPrefs,
 +                    hasRequiredUserPrefs: hasRequiredUserPrefs
 +                });
 +                var $markup = $(markup);
 +
 +                $('.prefs-save-button', $markup).click({id: widgetDefinition.regionWidgetId},
 +                    saveEditPrefsAction);
 +
 +                $('.prefs-cancel-button', $markup).click({id: widgetDefinition.regionWidgetId},
 +                    cancelEditPrefsAction);
 +
 +                var prefsElement = $("#widget-" + widgetDefinition.regionWidgetId + "-prefs-content");
 +                prefsElement.html($markup);
 +
 +                prefsElement.show();
 +            }
 +
 +            function saveEditPrefsAction(args) {
 +                var definition = widget;
 +                var prefsElement = $("#" + WIDGET_PREFS_CONTENT(definition.regionWidgetId));
 +
 +                var updatedPrefs = {};
 +                var hasValidationErrors = false;
 +                // note that validation of "required" prefs is only done for text and
 +                // textarea types, since those represent STRING and LIST inputs, and
 +                // are the only inputs that could potentially contain empty data
 +                prefsElement.find("*").filter(":input").each(function (index, element) {
 +                    switch (element.type) {
 +                        case "text":
 +                            if (!validatePrefInput(element)) {
 +                                hasValidationErrors = true;
 +                                $(element).addClass(WIDGET_PREFS_INPUT_FAILED_VALIDATION);
 +                            } else {
 +                                updatedPrefs[element.name] = $(element).val();
 +                                $(element).removeClass(WIDGET_PREFS_INPUT_FAILED_VALIDATION);
 +                            }
 +                            break;
 +                        case "select-one":
 +                        case "hidden":
 +                            updatedPrefs[element.name] = $(element).val();
 +                            break;
 +                        case "checkbox":
 +                            updatedPrefs[element.name] = $(element).is(':checked').toString();
 +                            break;
 +                        case "textarea":
 +                            if (!validatePrefInput(element)) {
 +                                hasValidationErrors = true;
 +                                $(element).addClass(WIDGET_PREFS_INPUT_FAILED_VALIDATION);
 +                            } else {
 +                                var valuesToPersist = [];
 +                                var textareaValues = $(element).val().split("\n");
 +                                for (var i = 0; i < textareaValues.length; i++) {
 +                                    var value = $.trim(textareaValues[i]);
 +                                    if (value.length > 0) {
 +                                        valuesToPersist.push(value);
 +                                    }
 +                                }
 +                                updatedPrefs[element.name] = valuesToPersist.join("|");
 +                                $(element).removeClass(WIDGET_PREFS_INPUT_FAILED_VALIDATION);
 +                            }
 +                            break;
 +                    }
 +                });
 +
 +                // check to see if one or more input prefs had validation errors
 +                if (hasValidationErrors) {
 +                    // focus on the first input that has validation errors
 +                    prefsElement.find("." + WIDGET_PREFS_INPUT_FAILED_VALIDATION).first().focus();
 +                } else {
 +                    if (ravePortal.isPageEditor()) {
 +                        widget.savePreferences(updatedPrefs);
 +                        widget.render(widget._el);
 +                    }
 +
 +                    prefsElement.html("");
 +                    prefsElement.hide();
 +                }
 +            }
 +
 +            function cancelEditPrefsAction(args) {
 +                var prefsElement = $("#" + WIDGET_PREFS_CONTENT(args.data.id));
 +                prefsElement.html("");
 +                prefsElement.hide();
 +            }
 +
 +            function validatePrefInput(element) {
 +                var isValid = true;
 +                var jqEl = $(element);
 +                // if the input is required verify it's trimmed input length is > 0
 +                if (jqEl.hasClass(WIDGET_PREFS_INPUT_REQUIRED_CLASS)) {
 +                    isValid = $.trim(jqEl.val()).length > 0;
 +                }
 +
 +                return isValid;
 +            }
 +        }
 +
 +        function registerHomeView() {
 +
 +            rave.RegionWidget.extend({
 +                renderError: function (el, errors) {
 +                    el.innerHTML = ravePortal.getClientMessage("opensocial.render_error") + "<br /><br />" + errors;
 +                }
 +            });
 +
 +            var HomeView = function (widget) {
 +                this.widget = widget;
 +
 +                var regionWidgetId = widget.regionWidgetId;
 +
 +                this.$chrome = $('#widget-' + regionWidgetId + '-wrapper');
 +                this.$minimizeIcon = $("#widget-" + regionWidgetId + "-min");
 +                this.$toggleCollapseIcon = $("#widget-" + regionWidgetId + "-collapse");
 +                this.$cogIcon = $('#widget-'+regionWidgetId+'-menu-button');
 +                this.$menuItemMove = $("#widget-" + regionWidgetId + "-menu-move-item");
 +                this.$menuItemDelete = $("#widget-" + regionWidgetId + "-menu-delete-item");
 +                this.$menuItemMaximize = $("#widget-" + regionWidgetId + "-menu-maximize-item");
 +                this.$menuItemAbout = $("#widget-" + regionWidgetId + "-menu-about-item");
 +                this.$menuItemComment = $("#widget-" + regionWidgetId + "-menu-comment-item");
 +                this.$menuItemRate = $("#widget-" + regionWidgetId + "-menu-rate-item");
 +                this.$menuItemEditPrefs = $("#widget-" + regionWidgetId + "-menu-editprefs-item");
 +                this.$widgetSite = $("#widget-" + regionWidgetId + "-body");
 +                this.$title = $("#widget-" + regionWidgetId + "-title");
 +            }
 +
 +            HomeView.prototype.render = function (widget) {
 +                var regionWidgetId = this.widget.regionWidgetId;
 +                var widgetId = this.widget.widgetId;
 +                var self = this;
 +
 +                doCollapseExpand();
 +                cleanupFromCanvas();
 +
 +                function cleanupFromCanvas() {
 +                    $(".dnd-overlay, .canvas-overlay").remove();
 +                    getNonLockedRegions().sortable("option", "disabled", false);
 +                    // display the widget in normal view
 +                    $("#widget-" + regionWidgetId + "-wrapper").removeClass("widget-wrapper-canvas").addClass("widget-wrapper");
 +                    // hide the widget minimize button
 +                    $("#widget-" + regionWidgetId + "-min").hide();
 +                    // show the widget menu
 +                    $("#widget-" + regionWidgetId + "-widget-menu-wrapper").show();
 +                    // show the collapse/restore toggle icon
 +                    $("#widget-" + regionWidgetId + "-collapse").show();
 +                    // if the widget is collapsed execute the collapse function
 +                    // otherwise execute the minimize function
 +                    return false;
 +                }
 +
 +                function addIframeOverlays(event) {
 +                    //e.preventDefault();
 +
 +                    var i = 0;
 +                    $(".widget").each(function () {
 +                        var W = $(this).outerWidth(),
 +                            H = $(this).outerHeight(),
 +                            X = $(this).position().left,
 +                            Y = $(this).position().top;
 +
 +                        $(this).after('<div class="iframe-overlay" />');
 +                        $(this).next('.iframe-overlay').css({
 +                            width: W,
 +                            height: H,
 +                            position: "absolute",
 +                            top: Y,
 +                            left: X
 +                        });
 +
 +                    });
 +
 +                    $('.iframe-overlay').click(function () {
 +                        self.$cogIcon.dropdown('toggle');
 +                        $(".iframe-overlay").remove();
 +                    })
 +
 +                    // Remove any overlays onclick of all the things!!!
 +                    $("*:not(.dropdown-toggle)").on("click", function () {
 +                        $(".iframe-overlay").remove();
 +                    });
 +                }
 +
 +                function minimize() {
 +                    self.widget.render('home');
 +                }
 +
 +                function maximize() {
 +                    self.widget.render('canvas', {view: 'canvas'});
 +                }
 +
 +                function toggleCollapse() {
 +                    var hidden = self.widget.collapsed
 +                    if (hidden) {
 +                        self.widget.show();
 +                    }
 +                    else {
 +                        self.widget.hide();
 +                    }
 +                    doCollapseExpand();
 +                    return false;
 +                }
 +
 +                function doCollapseExpand() {
 +                    var expanded = !widget.collapsed
 +                    $(self.$widgetSite).toggle(expanded);
 +                    $('i', self.$toggleCollapseIcon).toggleClass('icon-chevron-down', expanded);
 +                    $('i', self.$toggleCollapseIcon).toggleClass('icon-chevron-up', !expanded);
 +                }
 +
 +                function showMovePageDialog() {
 +                    // Clear the dropdown box; needing to do self may be a bug?
 +                    $('.dropdown').removeClass('open');
 +                    // Open the modal
 +                    $("#moveWidgetModal").data('regionWidgetId', regionWidgetId);
 +                    $("#moveWidgetModal").modal('show');
 +
 +                    return false;
 +                }
 +
 +                function deleteWidget() {
 +                    self.widget.close();
 +                    return false;
 +                }
 +
 +                function aboutWidget() {
 +                    ravePortal.viewWidgetDetail(widgetId, rave.getPage().id);
 +                    return false;
 +                }
 +
 +                function commentOnWidget() {
 +                    ravePortal.viewWidgetDetail(widgetId, rave.getPage().id, 'widgetComments');
 +                    return false;
 +                }
 +
 +                function rateWidget() {
 +                    ravePortal.viewWidgetDetail(widgetId, rave.getPage().id, 'widgetRatings');
 +                    return false;
 +                }
 +
 +                function showPrefsPane() {
 +                    showWidgetPrefs(widget);
 +                    return false;
 +                }
 +
 +                $('#widget-' + regionWidgetId + '-toolbar').mousedown(function (event) {
 +                    // don't allow drag and drop when self item is clicked
 +                    event.stopPropagation();
 +                });
 +
 +                //bind widget menu items
-                 self.$minimizeIcon.click(minimize);
-                 self.$toggleCollapseIcon.click(toggleCollapse);
++                self.$minimizeIcon.off("click").click(minimize);
++                self.$toggleCollapseIcon.off("click").click(toggleCollapse);
 +                self.$cogIcon.click(addIframeOverlays);
 +                self.$cogIcon.dropdown();
 +                if (!self.$menuItemMove.hasClass("menu-item-disabled")) {
-                     self.$menuItemMove.click(showMovePageDialog);
++                    self.$menuItemMove.off("click").click(getLaunchClosure(showMovePageDialog));
 +                }
 +                if (!self.$menuItemDelete.hasClass("menu-item-disabled")) {
-                     self.$menuItemDelete.click(deleteWidget);
++                    self.$menuItemDelete.off("click").click(getLaunchClosure(deleteWidget));
 +                }
 +                if (!self.$menuItemMaximize.hasClass("menu-item-disabled")) {
-                     self.$menuItemMaximize.click(maximize);
++                    self.$menuItemMaximize.off("click").click(getLaunchClosure(maximize));
 +                }
 +                if (!self.$menuItemAbout.hasClass("menu-item-disabled")) {
-                     self.$menuItemAbout.click(aboutWidget)
++                    self.$menuItemAbout.off("click").click(getLaunchClosure(aboutWidget));
 +                }
 +                if (!self.$menuItemComment.hasClass("menu-item-disabled")) {
-                     self.$menuItemComment.click(commentOnWidget);
++                    self.$menuItemComment.off("click").click(getLaunchClosure(commentOnWidget));
 +                }
 +                if (!self.$menuItemRate.hasClass("menu-item-disabled")) {
-                     self.$menuItemRate.click(rateWidget);
++                    self.$menuItemRate.off("click").click(getLaunchClosure(rateWidget));
 +                }
 +                var metadata = self.widget.metadata;
 +                if (metadata && (metadata.hasPrefsToEdit || (metadata.views && metadata.views.preferences))) {
 +                    self.$menuItemEditPrefs.removeClass("menu-item-disabled");
-                     self.$menuItemEditPrefs.click(showPrefsPane);
++                    self.$menuItemEditPrefs.off("click").click(getLaunchClosure(showPrefsPane));
 +                }
++
++                function getLaunchClosure(fn) {
++                    return function(evt) {
++                        self.$cogIcon.dropdown();
++                        fn(evt);
++                    }
++                }
++
 +            }
 +            HomeView.prototype.getWidgetSite = function () {
 +                return this.$widgetSite[0];
 +            }
 +            HomeView.prototype.destroy = function (widget) {
 +                this.$chrome.remove();
 +                if (ravePortal.isPageEmpty()) {
 +                    displayEmptyPageMessage();
 +                }
 +            }
 +            HomeView.prototype.expand = function () {
 +                this.$chrome.show();
 +            }
 +            HomeView.prototype.collapse = function () {
 +                this.$chrome.hide();
 +            }
 +            HomeView.prototype.setTitle = function(title) {
 +                this.$title.html(title);
 +            }
 +
 +            rave.registerView('home', HomeView);
 +        }
 +
 +        function registerCanvasView() {
 +            var CanvasView = function (widget) {
 +                this.widget = widget;
 +                this.$title = $("#widget-" + widget.regionWidgetId + "-title");
 +            }
 +            CanvasView.prototype.render = function (widget) {
 +                this.widget = widget;
 +                // display the widget in maximized view
 +                openFullScreenOverlay(widget.regionWidgetId);
 +                // due to widget list changing height of the window, we have to set the height of the sneeze-guard here.
 +                var overlayStyleMap = {
 +                    height: $('.wrapper').height() - $('.navbar').height() - $('.logo-wrapper').height()
 +                };
 +                $('.canvas-overlay').css(overlayStyleMap);
 +
 +                widget.render(widget._el, {view: 'canvas'});
 +
 +                function openFullScreenOverlay(widgetId) {
 +                    addCanvasOverlay($("#pageContent"));
 +                    getNonLockedRegions().sortable("option", "disabled", true);
 +                    $("#widget-" + widgetId + "-wrapper").removeClass("widget-wrapper").addClass("widget-wrapper-canvas");
 +                    // hide the widget menu
 +                    $("#widget-" + widgetId + "-widget-menu-wrapper").hide();
 +                    // display the widget minimize button
 +                    $("#widget-" + widgetId + "-min").show();
 +                    // hide the collapse/restore toggle icon in canvas mode
 +                    $("#widget-" + widgetId + "-collapse").hide();
 +                }
 +
 +                function addCanvasOverlay(jqElm) {
 +                    if ($('.canvas-overlay').length > 0) {
 +                        return;
 +                    }
 +                    var overlay = $('<div></div>');
 +                    var styleMap = {
 +                        height: $('body').height() - 40
 +                    };
 +
 +                    // style it and give it the marker class
 +                    $(overlay).css(styleMap);
 +                    $(overlay).addClass("canvas-overlay");
 +                    // add it to the dom before the iframe so it covers it
 +                    jqElm.prepend(overlay[0]);
 +                }
 +            }
 +            CanvasView.prototype.getWidgetSite = function () {
 +                return $("#widget-" + this.widget.regionWidgetId + "-body")[0];
 +            }
 +            CanvasView.prototype.destroy = function () {
 +                $(".dnd-overlay, .canvas-overlay").remove();
 +                getNonLockedRegions().sortable("option", "disabled", false);
 +                // display the widget in normal view
 +                $("#widget-" + widgetId + "-wrapper").removeClass("widget-wrapper-canvas").addClass("widget-wrapper");
 +                // hide the widget minimize button
 +                $("#widget-" + widgetId + "-min").hide();
 +                // show the widget menu
 +                $("#widget-" + widgetId + "-widget-menu-wrapper").show();
 +                // show the collapse/restore toggle icon
 +                $("#widget-" + widgetId + "-collapse").show();
 +                // if the widget is collapsed execute the collapse function
 +                // otherwise execute the minimize function
 +                return false;
 +            }
 +            CanvasView.prototype.setTitle  = function(title) {
 +                this.$title.html(title);
 +            }
 +
 +            rave.registerView('canvas', CanvasView);
 +        }
 +
 +        function registerPopups() {
 +            var POPUPS = {
 +                sidebar: {
 +                    name: "sidebar",
 +                    containerSelector: '.popup.slideout',
 +                    contentSelector: '.slideout-content',
 +                    template: 'popup-slideout',
 +                    initialize: function (container) {
 +                        var self = this;
 +                        var content = container.find(this.contentSelector);
 +                        content.data('popupType', this.name);
 +                        container.find('.close').click(function () {
 +                            self.cleanup(content);
 +                        });
 +                        container.show("slide", { direction: "right" }, 'fast');
 +                        $('body').addClass('modal-open');
 +                        $('body').append('<div class="modal-backdrop fade in"></div>');
 +                        // hide the main browser window's scrollbar to prevent possible "double scrollbar" rendering
 +                        // between it and an iframe vertical scrollbar
 +                        $('body').addClass('no-scroll');
 +                    },
 +                    cleanup: function (content) {
 +                        var container = content.parents(this.containerSelector);
 +                        container.hide("slide", { direction: "right" }, 'fast', function () {
 +                            container.remove();
 +                            $('body').removeClass('modal-open');
 +                            $('.modal-backdrop').remove();
 +                            // restore the main browser window's scrollbar
 +                            $('body').removeClass('no-scroll');
 +                        });
 +                    },
 +                    singleton: true
 +                },
 +                dialog: {
 +                    name: "dialog",
 +                    containerSelector: '.popup.dialog',
 +                    contentSelector: '.modal-body',
 +                    template: 'popup-dialog',
 +                    initialize: function (container) {
 +                        container.find(this.contentSelector).data('popupType', this.name);
 +                        var cfg = {
 +                        };
 +                        container.modal(cfg);
 +
 +                        container.on('hidden', function () {
 +                            container.remove();
 +                        })
 +                    },
 +                    cleanup: function (content) {
 +                        var container = content.parents(this.containerSelector);
 +
 +                        container.modal('hide');
 +                    },
 +                    singleton: false
 +                },
 +                modal_dialog: {
 +                    name: "modal_dialog",
 +                    containerSelector: '.popup.modal_dialog',
 +                    contentSelector: '.modal-body',
 +                    template: 'popup-modal',
 +                    initialize: function (container) {
 +                        container.find(this.contentSelector).data('popupType', this.name);
 +                        var cfg = {
 +                            keyboard: false,
 +                            backdrop: 'static',
 +                            show: true
 +                        };
 +                        container.modal(cfg);
 +
 +                        container.on('hidden', function () {
 +                            container.remove();
 +                        })
 +                    },
 +                    cleanup: function (content) {
 +                        var container = content.parents(this.containerSelector);
 +
 +                        container.modal('hide');
 +                    },
 +                    singleton: true
 +                }
 +            };
 +
 +            _.each(POPUPS, function (target) {
 +                var $container,
 +                    $site;
 +
 +                rave.registerView(target.name, {
 +                    render: function (prefs) {
 +                        $container = $(raveTemplates.templates[target.template]());
 +                        $site = $(target.contentSelector, $container);
 +
 +                        var height = (prefs && prefs.preferredHeight);
 +                        var width = (prefs && prefs.preferredWidth);
 +                        if (height) {
 +                            $container.height(height);
 +                        }
 +                        if (width) {
 +                            $container.width(width);
 +                        }
 +                        $("#pageContent").prepend($container);
 +
 +                        if (_.isFunction(target.initialize)) {
 +                            target.initialize($container)
 +                        }
 +                        return this;
 +                    },
 +                    getWidgetSite: function () {
 +                        return $site[0];
 +                    },
 +                    destroy: function () {
 +                        if (_.isFunction(target.cleanup)) {
 +                            target.cleanup($site);
 +                        }
 +                        else {
 +                            $container.remove();
 +                        }
 +                    }
 +                });
 +            });
 +        }
 +
++        function getActionElement(label, image, tooltip) {
++            var elem;
++            if(image) {
++                if(image.indexOf("css") === 0) {
++                    elem = '<i class="' + image.replace("css:","") + '" ></i>';
++                } else {
++                    elem = '<img src="' + image + '" />';
++                }
++            } else {
++                elem = "<a>" + label + "</a>";
++            }
++            return $(elem).attr("tooltip", tooltip);
++        }
++
++        function insertWidgetToolbarAction(widgetId, label, image, tooltip, id, onSelected) {
++            var $toolbar = $("#widget-" + widgetId + "-wrapper .widget-title-bar");
++            var $action = $('<div class="widget-titlebar-action widget-toolbar" ></div>').append(getActionElement(label, image, tooltip));
++            $action.attr("id", id).on('click', onSelected);
++            $toolbar.append($action);
++            return $action;
++        }
++
++        function registerActionsHandler() {
++            var actions = {};
++            rave.registerActionHandler({
++                create: function(id, label, path, widgetId, image, tooltip, onSelected) {
++                    if(!actions[id]) {
++                        var segments = path.split("/");
++                        //TODO Implement more paths and a better path routing system
++                        if (segments.length === 2 && segments[0] === "widget" && segments[1] === "toolbar") {
++                            actions[id] = insertWidgetToolbarAction(widgetId, label, image, tooltip, id, onSelected);
++                        } else {
++                            rave.log("Unsupported action path: '" + path + "'")
++                        }
++                    }
++                },
++                remove: function(id) {
++                    if(actions[id]) actions[id].remove();
++                }
++            });
++        }
++
 +        function init() {
 +            initializePageSharing();
 +            registerHomeView();
 +            registerCanvasView();
 +            registerPopups();
 +            showEmptyDisplay();
 +            setupDragAndDrop();
++            registerActionsHandler();
 +        }
 +
 +        rave.registerOnInitHandler(init);
 +
 +        return exports;
 +    })

http://git-wip-us.apache.org/repos/asf/rave/blob/5344cc71/rave-portal-resources/src/main/webapp/static/script/requireConfig.js
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/rave/blob/5344cc71/rave-portal/pom.xml
----------------------------------------------------------------------
diff --cc rave-portal/pom.xml
index a31e12e,34df05a..13cbc60
--- a/rave-portal/pom.xml
+++ b/rave-portal/pom.xml
@@@ -24,7 -24,7 +24,7 @@@
      <parent>
          <groupId>org.apache.rave</groupId>
          <artifactId>rave-project</artifactId>
-         <version>0.23-ANGULAR-SNAPSHOT</version>
 -        <version>0.24-SNAPSHOT</version>
++        <version>0.24-ANGULAR-SNAPSHOT</version>
      </parent>
  
      <artifactId>rave-portal</artifactId>

http://git-wip-us.apache.org/repos/asf/rave/blob/5344cc71/rave-providers/pom.xml
----------------------------------------------------------------------
diff --cc rave-providers/pom.xml
index d1c34b5,91b14df..6cf3f7a
--- a/rave-providers/pom.xml
+++ b/rave-providers/pom.xml
@@@ -26,7 -26,7 +26,7 @@@
      <parent>
          <groupId>org.apache.rave</groupId>
          <artifactId>rave-project</artifactId>
-         <version>0.23-ANGULAR-SNAPSHOT</version>
 -        <version>0.24-SNAPSHOT</version>
++        <version>0.24-ANGULAR-SNAPSHOT</version>
      </parent>
  
      <artifactId>rave-providers</artifactId>

http://git-wip-us.apache.org/repos/asf/rave/blob/5344cc71/rave-providers/rave-opensocial-provider/pom.xml
----------------------------------------------------------------------
diff --cc rave-providers/rave-opensocial-provider/pom.xml
index db154f5,63411bf..34f82c1
--- a/rave-providers/rave-opensocial-provider/pom.xml
+++ b/rave-providers/rave-opensocial-provider/pom.xml
@@@ -26,7 -26,7 +26,7 @@@
      <parent>
          <artifactId>rave-providers</artifactId>
          <groupId>org.apache.rave</groupId>
-         <version>0.23-ANGULAR-SNAPSHOT</version>
 -        <version>0.24-SNAPSHOT</version>
++        <version>0.24-ANGULAR-SNAPSHOT</version>
      </parent>
  
      <artifactId>rave-opensocial-provider</artifactId>

http://git-wip-us.apache.org/repos/asf/rave/blob/5344cc71/rave-providers/rave-opensocial-provider/rave-opensocial-client/pom.xml
----------------------------------------------------------------------
diff --cc rave-providers/rave-opensocial-provider/rave-opensocial-client/pom.xml
index b99ee7d,68278e2..614f111
--- a/rave-providers/rave-opensocial-provider/rave-opensocial-client/pom.xml
+++ b/rave-providers/rave-opensocial-provider/rave-opensocial-client/pom.xml
@@@ -26,7 -26,7 +26,7 @@@
      <parent>
          <artifactId>rave-opensocial-provider</artifactId>
          <groupId>org.apache.rave</groupId>
-         <version>0.23-ANGULAR-SNAPSHOT</version>
 -        <version>0.24-SNAPSHOT</version>
++        <version>0.24-ANGULAR-SNAPSHOT</version>
      </parent>
  
      <artifactId>rave-opensocial-client</artifactId>

http://git-wip-us.apache.org/repos/asf/rave/blob/5344cc71/rave-providers/rave-opensocial-provider/rave-opensocial-core/pom.xml
----------------------------------------------------------------------
diff --cc rave-providers/rave-opensocial-provider/rave-opensocial-core/pom.xml
index 854975a,9b62b16..a519183
--- a/rave-providers/rave-opensocial-provider/rave-opensocial-core/pom.xml
+++ b/rave-providers/rave-opensocial-provider/rave-opensocial-core/pom.xml
@@@ -26,7 -26,7 +26,7 @@@
      <parent>
          <artifactId>rave-opensocial-provider</artifactId>
          <groupId>org.apache.rave</groupId>
-         <version>0.23-ANGULAR-SNAPSHOT</version>
 -        <version>0.24-SNAPSHOT</version>
++        <version>0.24-ANGULAR-SNAPSHOT</version>
      </parent>
  
      <artifactId>rave-opensocial-core</artifactId>

http://git-wip-us.apache.org/repos/asf/rave/blob/5344cc71/rave-providers/rave-opensocial-provider/rave-opensocial-server/pom.xml
----------------------------------------------------------------------
diff --cc rave-providers/rave-opensocial-provider/rave-opensocial-server/pom.xml
index 3066060,8ed21de..2d82e79
--- a/rave-providers/rave-opensocial-provider/rave-opensocial-server/pom.xml
+++ b/rave-providers/rave-opensocial-provider/rave-opensocial-server/pom.xml
@@@ -26,7 -26,7 +26,7 @@@
      <parent>
          <artifactId>rave-opensocial-provider</artifactId>
          <groupId>org.apache.rave</groupId>
-         <version>0.23-ANGULAR-SNAPSHOT</version>
 -        <version>0.24-SNAPSHOT</version>
++        <version>0.24-ANGULAR-SNAPSHOT</version>
      </parent>
  
      <artifactId>rave-opensocial-server</artifactId>

http://git-wip-us.apache.org/repos/asf/rave/blob/5344cc71/rave-providers/rave-opensocial-provider/rave-opensocial-server/rave-shindig-dependencies/pom.xml
----------------------------------------------------------------------
diff --cc rave-providers/rave-opensocial-provider/rave-opensocial-server/rave-shindig-dependencies/pom.xml
index 16337cc,0e35f19..95a4821
--- a/rave-providers/rave-opensocial-provider/rave-opensocial-server/rave-shindig-dependencies/pom.xml
+++ b/rave-providers/rave-opensocial-provider/rave-opensocial-server/rave-shindig-dependencies/pom.xml
@@@ -26,7 -26,7 +26,7 @@@
      <parent>
          <artifactId>rave-opensocial-server</artifactId>
          <groupId>org.apache.rave</groupId>
-         <version>0.23-ANGULAR-SNAPSHOT</version>
 -        <version>0.24-SNAPSHOT</version>
++        <version>0.24-ANGULAR-SNAPSHOT</version>
      </parent>
  
      <artifactId>rave-shindig-dependencies</artifactId>

http://git-wip-us.apache.org/repos/asf/rave/blob/5344cc71/rave-providers/rave-opensocial-provider/rave-opensocial-server/rave-shindig-resources/pom.xml
----------------------------------------------------------------------
diff --cc rave-providers/rave-opensocial-provider/rave-opensocial-server/rave-shindig-resources/pom.xml
index b1305f5,8ce3fff..3052150
--- a/rave-providers/rave-opensocial-provider/rave-opensocial-server/rave-shindig-resources/pom.xml
+++ b/rave-providers/rave-opensocial-provider/rave-opensocial-server/rave-shindig-resources/pom.xml
@@@ -26,7 -26,7 +26,7 @@@
      <parent>
          <artifactId>rave-opensocial-server</artifactId>
          <groupId>org.apache.rave</groupId>
-         <version>0.23-ANGULAR-SNAPSHOT</version>
 -        <version>0.24-SNAPSHOT</version>
++        <version>0.24-ANGULAR-SNAPSHOT</version>
      </parent>
  
      <artifactId>rave-shindig-resources</artifactId>

http://git-wip-us.apache.org/repos/asf/rave/blob/5344cc71/rave-providers/rave-opensocial-provider/rave-opensocial-server/rave-shindig/pom.xml
----------------------------------------------------------------------
diff --cc rave-providers/rave-opensocial-provider/rave-opensocial-server/rave-shindig/pom.xml
index faa668b,4fdb4c6..7e61355
--- a/rave-providers/rave-opensocial-provider/rave-opensocial-server/rave-shindig/pom.xml
+++ b/rave-providers/rave-opensocial-provider/rave-opensocial-server/rave-shindig/pom.xml
@@@ -26,7 -26,7 +26,7 @@@
      <parent>
          <groupId>org.apache.rave</groupId>
          <artifactId>rave-opensocial-server</artifactId>
-         <version>0.23-ANGULAR-SNAPSHOT</version>
 -        <version>0.24-SNAPSHOT</version>
++        <version>0.24-ANGULAR-SNAPSHOT</version>
      </parent>
  
      <artifactId>rave-shindig</artifactId>

http://git-wip-us.apache.org/repos/asf/rave/blob/5344cc71/rave-providers/rave-w3c-provider/pom.xml
----------------------------------------------------------------------
diff --cc rave-providers/rave-w3c-provider/pom.xml
index 66cfcac,8fbb6bf..f17debb
--- a/rave-providers/rave-w3c-provider/pom.xml
+++ b/rave-providers/rave-w3c-provider/pom.xml
@@@ -26,7 -26,7 +26,7 @@@
      <parent>
          <artifactId>rave-providers</artifactId>
          <groupId>org.apache.rave</groupId>
-         <version>0.23-ANGULAR-SNAPSHOT</version>
 -        <version>0.24-SNAPSHOT</version>
++        <version>0.24-ANGULAR-SNAPSHOT</version>
      </parent>
  
      <artifactId>rave-w3c-provider</artifactId>