Merge PR#14 from  'sieverssj/RAVE-1270'
diff --git a/rave-components/rave-core/src/main/java/org/apache/rave/portal/model/impl/PageImpl.java b/rave-components/rave-core/src/main/java/org/apache/rave/portal/model/impl/PageImpl.java
index c14790e..9e0b524 100644
--- a/rave-components/rave-core/src/main/java/org/apache/rave/portal/model/impl/PageImpl.java
+++ b/rave-components/rave-core/src/main/java/org/apache/rave/portal/model/impl/PageImpl.java
@@ -18,6 +18,8 @@
  */

 package org.apache.rave.portal.model.impl;

 

+import com.fasterxml.jackson.annotation.JsonBackReference;

+import com.fasterxml.jackson.annotation.JsonManagedReference;

 import org.apache.rave.model.*;

 

 import java.util.List;

@@ -28,8 +30,8 @@
     private String name;

     private String ownerId;

     private String contextId;

-    private Page parentPage;

-    private List<Page> subPages;

+    @JsonBackReference private Page parentPage;

+    @JsonManagedReference private List<Page> subPages;

     private PageLayout pageLayout;

     private List<Region> regions;

     private String pageType;

diff --git a/rave-components/rave-core/src/main/java/org/apache/rave/portal/service/PageService.java b/rave-components/rave-core/src/main/java/org/apache/rave/portal/service/PageService.java
index fadb17b..3ae4fe6 100644
--- a/rave-components/rave-core/src/main/java/org/apache/rave/portal/service/PageService.java
+++ b/rave-components/rave-core/src/main/java/org/apache/rave/portal/service/PageService.java
@@ -297,10 +297,10 @@
      * @param pageId   - the id of the page in question

      * @param userId   - the userid to add

      * @param pageName = name of the page

-     * @return true or false whether the user was added

+     * @return the newly cloned page

      */

     @PreAuthorize("hasPermission(#pageId, 'org.apache.rave.model.Page', 'update')")

-    Boolean clonePageForUser(String pageId, String userId, String pageName);

+    Page clonePageForUser(String pageId, String userId, String pageName);

 

     /**

      * Add another user to share this page with

diff --git a/rave-components/rave-core/src/main/java/org/apache/rave/portal/service/impl/DefaultPageService.java b/rave-components/rave-core/src/main/java/org/apache/rave/portal/service/impl/DefaultPageService.java
index 9ee4f60..9d6dff5 100644
--- a/rave-components/rave-core/src/main/java/org/apache/rave/portal/service/impl/DefaultPageService.java
+++ b/rave-components/rave-core/src/main/java/org/apache/rave/portal/service/impl/DefaultPageService.java
@@ -328,8 +328,9 @@
         return pageRepository.save(page);

     }

 

+    @Override

     @Transactional

-    public Boolean clonePageForUser(String pageId, String userId, String pageName) {

+    public Page clonePageForUser(String pageId, String userId, String pageName) {

         Page page = getPage(pageId);

         if(pageName == null || pageName.equals("null")){

             // try to use the original page name if none supplied

@@ -363,16 +364,21 @@
             }

         }

         clonedPage = getFromRepository(clonedPage.getId(), pageRepository);

+        if (clonedPage.getSubPages() == null) {

+            // Subpages should always be a list (even an empty one)

+            clonedPage.setSubPages(new ArrayList<Page>());

+        }

         clonedPage.setProperties(page.getProperties());

         // newly created page - so only one pageUser

         PageUser pageUser = clonedPage.getMembers().get(0);

         // update status to pending

-        pageUser.setPageStatus(PageInvitationStatus.PENDING);

-        if(pageRepository.save(clonedPage) != null){

-            return Boolean.TRUE;

-        }else{

-            return Boolean.FALSE;

+        User currentUser = userService.getAuthenticatedUser();

+        if (currentUser.getId().equals(user.getId())) {

+            pageUser.setPageStatus(PageInvitationStatus.OWNER);

+        } else {

+            pageUser.setPageStatus(PageInvitationStatus.PENDING);

         }

+        return pageRepository.save(clonedPage);

     }

 

     @Transactional

diff --git a/rave-components/rave-core/src/test/java/org/apache/rave/portal/service/impl/DefaultPageServiceTest.java b/rave-components/rave-core/src/test/java/org/apache/rave/portal/service/impl/DefaultPageServiceTest.java
index 1646fc6..66b180d 100644
--- a/rave-components/rave-core/src/test/java/org/apache/rave/portal/service/impl/DefaultPageServiceTest.java
+++ b/rave-components/rave-core/src/test/java/org/apache/rave/portal/service/impl/DefaultPageServiceTest.java
@@ -46,6 +46,7 @@
 import org.apache.rave.portal.repository.WidgetRepository;

 import org.apache.rave.portal.service.PageService;

 import org.apache.rave.portal.service.UserService;

+import org.easymock.Capture;

 import org.easymock.EasyMock;

 import org.easymock.IAnswer;

 import org.junit.Before;

@@ -1453,4 +1454,44 @@
 

         pageService.moveRegionWidgetToPage(VALID_REGION_WIDGET_ID, TO_PAGE_ID);

     }

+

+    @Test

+    public void clonePage_noRegions() {

+        PageLayout layout = new PageLayoutImpl("foobar");

+        layout.setNumberOfRegions(0L);

+        layout.setRenderSequence(1L);

+        page.setPageLayout(layout);

+        page.setRegions(new ArrayList<Region>());

+        page.setSubPages(new ArrayList<Page>());

+

+        expect(userService.getAuthenticatedUser()).andReturn(user);

+        expect(pageRepository.get(PAGE_ID)).andReturn(page);

+        List<Page> pages = Lists.newLinkedList();

+        pages.add(page);

+        expect(pageRepository.getAllPagesForUserType(user.getId(), "user")).andReturn(pages);

+        final Capture<Page> pageCapture = new Capture<Page>();

+        expect(pageRepository.save(capture(pageCapture))).andAnswer(new IAnswer<Page>() {

+            @Override

+            public Page answer() throws Throwable {

+                Page savedPage = (Page) EasyMock.getCurrentArguments()[0];

+                savedPage.setId("42");

+                return savedPage;

+            }

+        }).anyTimes();

+        expect(pageRepository.get("42")).andAnswer(new IAnswer<Page>() {

+            @Override

+            public Page answer() throws Throwable {

+                return pageCapture.getValue();

+            }

+        });

+

+        expect(pageLayoutRepository.getByPageLayoutCode("foobar")).andReturn(layout);

+        expect(userService.getUserById(user.getId())).andReturn(user);

+        replay(pageLayoutRepository, pageRepository, userService);

+

+        Page clonedPage = pageService.clonePageForUser(PAGE_ID, user.getId(), null);

+        assertEquals("ID matches", "42", clonedPage.getId());

+        assertEquals("Owner ID is set", user.getId(), clonedPage.getOwnerId());

+        assertEquals("Layout is set", "foobar", clonedPage.getPageLayout().getCode());

+    }

 }

diff --git a/rave-components/rave-web/src/main/java/org/apache/rave/portal/web/api/rpc/PageApi.java b/rave-components/rave-web/src/main/java/org/apache/rave/portal/web/api/rpc/PageApi.java
index 712456c..8fcd4fa 100644
--- a/rave-components/rave-web/src/main/java/org/apache/rave/portal/web/api/rpc/PageApi.java
+++ b/rave-components/rave-web/src/main/java/org/apache/rave/portal/web/api/rpc/PageApi.java
@@ -264,10 +264,10 @@
 

     @ResponseBody

     @RequestMapping(value = "{pageId}/clone", method = RequestMethod.POST)

-    public RpcResult<Boolean> clonePageForUser(@PathVariable final String pageId, @RequestParam final String userId, @RequestParam final String pageName) {

-        return new RpcOperation<Boolean>() {

+    public RpcResult<Page> clonePageForUser(@PathVariable final String pageId, @RequestParam final String userId, @RequestParam final String pageName) {

+        return new RpcOperation<Page>() {

              @Override

-             public Boolean execute() {

+             public Page execute() {

                return pageService.clonePageForUser(pageId, userId, pageName);

              }

         }.getResult();

diff --git 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
index 0952f7c..5b3d036 100644
--- 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
@@ -223,6 +223,7 @@
         exports.renderWidget = function (widget, el, opts) {
             if (widget.error) {
                 widget.renderError(el, widget.error.message);
+                opts && opts.callback && opts.callback({'error' : widget.error});
                 return;
             }
             opts = opts || {};
diff --git a/rave-portal-resources/src/main/webapp/static/script/portal/rave_ui.js b/rave-portal-resources/src/main/webapp/static/script/portal/rave_ui.js
index 61bb950..bd54ed5 100644
--- a/rave-portal-resources/src/main/webapp/static/script/portal/rave_ui.js
+++ b/rave-portal-resources/src/main/webapp/static/script/portal/rave_ui.js
@@ -232,7 +232,7 @@
                 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');
+                $(widgetEl).find('iframe').get(0).onload = function() {};
 
                 //for every drag operation, create an overlay for each iframe
                 //to prevent the iframe from intercepting mouse events
@@ -972,7 +972,7 @@
             } else {
                 elem = "<a>" + label + "</a>";
             }
-            return $(elem).attr("tooltip", tooltip);
+            return $(elem).attr("title", tooltip);
         }
 
         function insertWidgetToolbarAction(widgetId, label, image, tooltip, id, onSelected) {