This space is an archive space for documentation related to old versions of Fluid Infusion (i.e. versions before 1.3). For documentation related to the latest Infusion, see Infusion Documentation.

Integrating the Layout Customizer on uPortal

Demo environment: http://mercury.unicon.net:8080/uPortal/
Which is a uPortal 3.0.1 quickstart.

Steps for integrating the Layout Customizer

Upgrade the jQuery library

The later release of jQuery makes everything work better. Download and install jQuery 1.2.6, replacing the 1.2.3 files in the javascript directory. Change the jquery reference in the list of linked javacsript in TEMPLATE: PAGE JAVASCRIPT in universality.xsl (the main theme file).

Change from this:

<script type="text/javascript" src="{$SCRIPT_PATH}/jquery/jquery-1.2.3.min.js"></script>

To this:

<script type="text/javascript" src="{$SCRIPT_PATH}/jquery/jquery-1.2.6.min.js"></script>

In this template:

<!-- ========== TEMPLATE: PAGE JAVASCRIPT ========== -->
  <!-- =============================================== -->
  <!-- 
   | YELLOW
   | This template renders the Javascript links in the page <head>.
   | Javascript provides AJAX and enhanced client-side interaction to the portal.
   | Javascript files are located in the uPortal skins directory:
   | /media/skins/[theme_name]/common/javascript/
   | Template contents can be any valid XSL or XHTML.
  -->
  <xsl:template name="page.js">
    <xsl:if test="$USE_AJAX='true' or $USE_FLYOUT_MENUS='true'">
     <script type="text/javascript" src="{$SCRIPT_PATH}/jquery/jquery-1.2.3.min.js"></script>
    </xsl:if>
    <xsl:if test="$USE_AJAX='true' and $AUTHENTICATED='true'">
     <script type="text/javascript" src="{$SCRIPT_PATH}/jquery/jquery.dimensions.js"></script>
     <script type="text/javascript" src="{$SCRIPT_PATH}/jquery/ui.dialog.js"></script>
     <script type="text/javascript" src="{$SCRIPT_PATH}/jquery/ui.resizable.js"></script>
     <script type="text/javascript" src="{$SCRIPT_PATH}/jquery/ui.mouse.js"></script>
     <script type="text/javascript" src="{$SCRIPT_PATH}/jquery/ui.draggable.js"></script>
     <script type="text/javascript" src="{$SCRIPT_PATH}/jquery/ui.droppable.js"></script>
     <script type="text/javascript" src="{$SCRIPT_PATH}/jquery/ui.sortable.js"></script>
     <script type="text/javascript" src="{$SCRIPT_PATH}/jquery/ui.tabs.js"></script>
     <script type="text/javascript" src="{$SCRIPT_PATH}/jquery/interface.js"></script>
     <script type="text/javascript" src="{$SCRIPT_PATH}/ajax-preferences-jquery.js"></script>
     <script type="text/javascript" src="{$SCRIPT_PATH}/up-channel-browser.js"></script>
    </xsl:if>
  </xsl:template>

Javascript files are located at:

  • \media\skins\universality\common\javascript (deployed)
  • \uportal-war\src\main\webapp\media\skins\universality\common\javascript (source)

Theme files are located at:

  • \WEB-INF\classes\layout\theme\universality (deployed)
  • \uportal-war\src\main\resources\layout\theme\universality (source)

Disable the uPortal default drag and drop

Comment out the script that initializes the default drag and drop from ajax-preferences-jquery.js:

// initialize portlet drag and drop
//  ajaxPref('div[@id*=inner-column_]').each(function(i){
//    ajaxPref(this).Sortable({
//      accept : 'movable',
//      helperclass : 'dropborder',
//      opacity : 0.5,
//      handle : 'div.portlet-toolbar',
//      onStop : movePortlet
//    });
//  });

Javascript files are located at:

  • \media\skins\universality\common\javascript (deployed)
  • \uportal-war\src\main\webapp\media\skins\universality\common\javascript (source)

Add the Fluid Layout Customizer component

Add Fluid-all.js to the theme javascript directory.

Javascript files are located at:

  • \media\skins\universality\common\javascript (deployed)
  • \uportal-war\src\main\webapp\media\skins\universality\common\javascript (source)

Link to the Fluid component

Add this link to the Fluid-all.js file at the bottom of the list of linked javacsript in TEMPLATE: PAGE JAVASCRIPT in universality.xsl (the main theme file).

<!-- ========== TEMPLATE: PAGE JAVASCRIPT ========== -->
  <!-- =============================================== -->
  <!-- 
   | YELLOW
   | This template renders the Javascript links in the page <head>.
   | Javascript provides AJAX and enhanced client-side interaction to the portal.
   | Javascript files are located in the uPortal skins directory:
   | /media/skins/[theme_name]/common/javascript/
   | Template contents can be any valid XSL or XHTML.
  -->
  <xsl:template name="page.js">
    <xsl:if test="$USE_AJAX='true' or $USE_FLYOUT_MENUS='true'">
     <script type="text/javascript" src="{$SCRIPT_PATH}/jquery/jquery-1.2.6.min.js"></script>
    </xsl:if>
    <xsl:if test="$USE_AJAX='true' and $AUTHENTICATED='true'">
     <script type="text/javascript" src="{$SCRIPT_PATH}/jquery/jquery.dimensions.js"></script>
     <script type="text/javascript" src="{$SCRIPT_PATH}/jquery/ui.dialog.js"></script>
     <script type="text/javascript" src="{$SCRIPT_PATH}/jquery/ui.resizable.js"></script>
     <script type="text/javascript" src="{$SCRIPT_PATH}/jquery/ui.mouse.js"></script>
     <script type="text/javascript" src="{$SCRIPT_PATH}/jquery/ui.draggable.js"></script>
     <script type="text/javascript" src="{$SCRIPT_PATH}/jquery/ui.droppable.js"></script>
     <script type="text/javascript" src="{$SCRIPT_PATH}/jquery/ui.sortable.js"></script>
     <script type="text/javascript" src="{$SCRIPT_PATH}/jquery/ui.tabs.js"></script>
     <script type="text/javascript" src="{$SCRIPT_PATH}/jquery/interface.js"></script>
     <script type="text/javascript" src="{$SCRIPT_PATH}/ajax-preferences-jquery.js"></script>
     <script type="text/javascript" src="{$SCRIPT_PATH}/up-channel-browser.js"></script>
     <script type="text/javascript" src="{$SCRIPT_PATH}/Fluid-all.js"></script>
    </xsl:if>
  </xsl:template>

Theme files are located at:

  • \WEB-INF\classes\layout\theme\universality (deployed)
  • \uportal-war\src\main\resources\layout\theme\universality (source)

Add drop warning for locked content

Add the following html for the drop warning message in TEMPLATE: FOOTER BLOCK in universality.xsl (the main theme file):

  <!-- ========== TEMPLATE: FOOTER BLOCK ========== -->
  <!-- ============================================ -->
  <!-- 
   | GREEN
   | This template renders custom content into the page footer.
   | Template contents can be any valid XSL or XHTML.
  -->
  <xsl:template name="footer.block">
     ...
      <div id="portalDropWarning">
         <p>The box cannot be moved here. The box currently located here is locked.</p>
      </div>
    
  </xsl:template>
  <!-- ============================================ -->

Theme files are located at:

  • \WEB-INF\classes\layout\theme\universality (deployed)
  • \uportal-war\src\main\resources\layout\theme\universality (source)

Add initialization script

Add the following initialization script in TEMPLATE: FOOTER BLOCK in universality.xsl (the main theme file):

 
<xsl:if test="$USE_AJAX='true' and $AUTHENTICATED='true'">
   <script type="text/javascript">
      var grabHandle = function (item) {
         // the handle is the toolbar. The toolbar id is the same as the portlet id, with the
         // "portlet_" prefix replaced by "toolbar_".
         return jQuery ("[id=toolbar_" + item.id.split ("_")[1] + "]");
      };
               
      var options = {
         cssClassNames: {
            mouseDrag: "orderable-dragging-mouse"
         },
      grabHandle: grabHandle,
      dropWarningId: "portalDropWarning"
      };
               
      fluid.reorderLayout ("#portalPageBodyColumns", {
         columns: ".portal-page-column-inner",
         modules: ".portlet-container ",
         lockedModules: ".locked"
      }, movePortlet, options);
   </script>
</xsl:if>

Note that this script must come after the drop warning html in order for the drop warning message to work:

  <!-- ========== TEMPLATE: FOOTER BLOCK ========== -->
  <!-- ============================================ -->
  <!-- 
   | GREEN
   | This template renders custom content into the page footer.
   | Template contents can be any valid XSL or XHTML.
  -->
  <xsl:template name="footer.block">
     ...
      <div id="portalDropWarning">
         <p>The box cannot be moved here. The box currently located here is locked.</p>
      </div>
      
      <xsl:if test="$USE_AJAX='true' and $AUTHENTICATED='true'">
         <script type="text/javascript">
            ...
         </script>
      </xsl:if>
  </xsl:template>
  <!-- ============================================ -->

The xsl:if statement ensures that this script does not load improperly and cause a javascript error in the browser. This script:

  • sets the drag handle to just the portlet title bar
  • sets an optional css class for the mouse drag state (to avoid a error in the keyboard reordering)
  • sets use of the grabHandle option
  • sets use of the dropWarning option
  • specifies the uPortal html ids and classes to map as drag items and drop areas

Theme files are located at:

  • \WEB-INF\classes\layout\theme\universality (deployed)
  • \uportal-war\src\main\resources\layout\theme\universality (source)

Add CSS

Add the following CSS to uportal3.css (the main css file).

 
/* Locked portlet styles */
.portal-page-column-inner .locked .portlet-top {display:none;}
.portal-page-column-inner .locked .portlet-bottom {display:none;}
.portal-page-column-inner .locked .portlet-toolbar {background-color:#ddd;border:1px solid #999;}
.portal-page-column-inner .locked .portlet-toolbar a {color:#333;}
.portal-page-column-inner .locked .portlet-toolbar h2 {background:transparent url("../../icons/lock.png") 0 3px no-repeat;}
.portal-page-column-inner .locked .portlet-controls {background-color:transparent;}
.dashboard .portal-page-column-inner .locked .portlet-content {border:1px solid #999;}


/* Fluid Layout Customizer styles */
.orderable-hover{cursor:move;}
.orderable-dragging{filter:alpha(opacity=50); opacity:.5;}
.orderable-dragging-mouse{display:none;}
.orderable-selected{}
.orderable-avatar {width:auto; filter:alpha(opacity=50); opacity:.5;}
div .orderable-drop-marker{height:200px !important; background-color: #99FF99; border:1px dashed #00CC00; margin:1em 0em;}
.orderable-avatar-clone {height:200px; width:400px; filter:alpha(opacity=60); opacity:.6;}
.drop-warning {position:absolute; top:50px; left:10px; border:2px solid red; background-color:#ffd7d7; display:none; padding:10px; margin:5px; z-index:65535;}
.orderable-drop-marker-box {height:200px !important; width:100%; border:2px dashed red; margin-bottom:1em; background-color:#ffd7d7;}
.orderable-mouse-drag {display: none;}
#portalDropWarning{background-color:#FFCCCC; border:2px solid #FF0000; color:#FF0000; display:none; position:absolute; top:50px; left:10px;}
#portalDropWarning p{margin:0em; padding:0.5em 1em;}

Skin files are located at:

  • \webapps\uPortal\media\skins\universality\uportal3 (deployed)
  • \uportal-war\src\main\webapp\media\skins\universality\uportal3 (source)

Add AJAX callback

AJAX callback for persisting layout changes is added to ajax-preferences-jquery.js. Replace the existing movePortlet function with this one:

function movePortlet(movedNode) {
   var method = 'insertBefore';
   var target = null;
   if (ajaxPref(movedNode).nextAll('div[@id*=portlet_]').size() > 0) {
       target = ajaxPref(movedNode).nextAll('div[@id*=portlet_]').get(0);
   } else if (ajaxPref(movedNode).prevAll('div[@id*=portlet_]').size() > 0) {
       target = ajaxPref(movedNode).prevAll('div[@id*=portlet_]').get(0);
       method = 'appendAfter';
   } else {
       target = ajaxPref(movedNode).parent();
   }
   var columns = ajaxPref('#portalPageBodyColumns > td[@id*=column_]');
   for (var i = 0; i < columns.length; i++) {
       ajaxPref(columns[i]).attr("width", ajaxPref(columns[i]).attr("width"));
   }
   ajaxPref.post(preferencesUrl, {action: 'movePortletHere', method: method, elementID: ajaxPref(target).attr('id').split('_')[1], sourceID: ajaxPref(movedNode).attr('id').split('_')[1]}, function(xml) { });
} 

Javascript files are located at:

  • \media\skins\universality\common\javascript (deployed)
  • \uportal-war\src\main\webapp\media\skins\universality\common\javascript (source)

Tune the environment

Integration to this point enabled the Layout Customizer to work, but broke other uPortal AJAX functionality (flyout menus and AJAX layout customization). Better namespacing of the uPortal Javascript (using jQuery.noConflict) fixed everything but Add Content, which for the demo environment was simply commented out like so (contentAddingDialog):

// Initialization tasks for non-focused mode
function initportal() {

	// initialize dialog menus
	// ajaxPref("#contentAddingDialog").channelbrowser({handles: new Array("#contentDialogLink")});
	ajaxPref("#layoutDialogLink").click(initializeLayoutMenu);
	ajaxPref("#skinDialogLink").click(initializeSkinMenu);
	...
}