You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@tapestry.apache.org by Joshua Long <lh...@adelphia.net> on 2005/03/05 14:29:23 UTC

An Outlook bar component dontation. Code enclosed.

Alright,so, guys, I have a REALLY hacked up Outlook bar component to
donate, as well. 

Essentially, the JS used to generate it isn't super conductive to having
more than one instance per page. IE, it's only good for one use per
page, though, for our purposes, this was fine. Even if the js had been
amenable to more than one use per page, however, i doubt the code would
have suffered it.. 

Disclaimer: I developed this for my purposes. It works fine on Mozilla,
IE, Firefox. It is, however, something developeriteratively and there
are chunks where, while not used at all anymore, still remain inthe code
simply because i didn't delete much. I just kept going until it worked. 

On the upside it is pretty cool

It renders an outlook bar, which contain panels, which in turn contain
links. The links have icons, and a link. The url has support for being a
restart service link, a page link, or a direct link. It's pretty evil
actually =) It remembers what state it's in, but it does it by
resubmitting. Thus, if you toggle a panel, it submits and, on reload,
the js kicks in to RESTORE state. If you click a link, it submits.
Essentially, i didn't simply have a form used to track the state on the
client because this offered the pat of least resistance (that's my story
and I'm sticking with it...) 

Anyway, I'm sure you guys can do some amazing things with it if you
wanted to. I got it working quickly for a demo and as such it's not very
polished... 


Anyway, I hope this helps someone. I'm licensing it under the
do-whatever-you-want-with-it-but-remember
your-old-pal-Josh-when-you-win-the-lottery-or-make-cool-changes-to-it
license.


Joshua Long 
josh@joshlong.com 




ANYWAY: heres the code...


// example use of the component(s) in our Border component looks like 

<div jwcid="@OutlookBar">

     <!-- a pane, there can be many panes-->
  <div jwcid="@OutlookPane" title="Inbox" >
    <!-- to emit a page link -->
    <a href="#" jwcid="@OutlookLink" page="ReadEmailPage"
image="ognl:assets.email"> Read Email </a>
     <!-- to emit a link that has a listener --> 
    <a href="#" jwcid="@OutlookLink"  
listener="ognl:listeners.editLoggedInAgentAction" 
image="ognl:assets.statistics"> Update Profile  </a>
    </div>


     <div jwcid="@OutlookPane" title = "Contacts" >
            <a href=# jwcid="@OutlookLink" listener =
"ognl:listeners.loginToContactManager">  Contact Manager </a> 
         
       </div>

 
     </div>










/// ------------------------------------
/// Java code 
/// ------------------------------------



/////// the first thing is a utlity base class that the components use

package com.roartechnologies.ap.view.components;

import org.apache.tapestry.BaseComponent;
import org.apache.tapestry.IAsset;
import org.apache.tapestry.IRequestCycle;

import java.text.DateFormat;
import java.text.MessageFormat;
import java.text.NumberFormat;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.logging.Logger;

 /**
  * @author Joshua Long (josh@joshlong.com)
  * 
  * A utility base class. 
  * 
  * Should this be a third class? Yes. 
  * But either way you'd be stuck 
  * with an extra dependency...
  * 
  */ 
public class FoyerBaseComponent extends BaseComponent {
    private DateFormat timeFormatter = DateFormat.getDateTimeInstance();

    public DateFormat getTimeFormatter() {
        return timeFormatter;
    }

    public void setTimeFormatter(DateFormat timeFormatter) {
        this.timeFormatter = timeFormatter;
    }

    private NumberFormat percentFormatter =
NumberFormat.getPercentInstance();
    private NumberFormat numberFormatter =
NumberFormat.getNumberInstance();

    public DateFormat getDateFormatter() {
        return dateFormatter;
    }

    public void setDateFormatter(DateFormat dateFormatter) {
        this.dateFormatter = dateFormatter;
    }

    private DateFormat dateFormatter =
DateFormat.getDateInstance(DateFormat.SHORT);


    public NumberFormat getNumberFormatter() {
        return numberFormatter;
    }

    public void setNumberFormatter(NumberFormat numberFormatter) {
        this.numberFormatter = numberFormatter;
    }

    public NumberFormat getPercentFormatter() {
        return percentFormatter;
    }

    public void setPercentFormatter(NumberFormat percentFormatter) {
        this.percentFormatter = percentFormatter;
    }


    protected Map getSymbolsForAssets(Map assets, IRequestCycle cycle) {
        Map img_sys = new HashMap(assets.size());
        Set keys = assets.keySet();
        Iterator it = keys.iterator();
        while (it.hasNext()) {
            String key = (String) it.next();
            IAsset ass = (IAsset) assets.get(key);
            String URL = ass.buildURL(cycle);
            img_sys.put(key, URL);
        }
        return img_sys;
    }


    protected void prepareForRender(IRequestCycle cycle) {
        super.prepareForRender(cycle);
        setupComponent(cycle);
    }

    protected void setupComponent(IRequestCycle cycle) {
    }

    private static final Logger log =
            Logger.getLogger(FoyerBaseComponent.class.getName());

    protected void log(String msg) {
        log.info(msg);
    }

    protected void log(String msg, Object[] prop) {
        log(MessageFormat.format(msg, prop));
    }

    protected void error(Throwable thr) {
        /* 
         * This used to use the apache commons' excellent
         * ExceptionUtils.getStackTrace(), but, 
         * to remove an extra dependancy, 
         * I changed it for you 
         */
        log(thr.getMessage());
        thr.printStackTrace();
    }
}






  /// outlook bar
package com.roartechnologies.ap.view.components.outlookbar;

import com.roartechnologies.ap.view.components.FoyerBaseComponent;
import org.apache.tapestry.IRequestCycle;
import org.apache.tapestry.IResourceLocation;
import org.apache.tapestry.IScript;
import org.apache.tapestry.engine.IScriptSource;
import org.apache.tapestry.html.Body;

import javax.servlet.http.HttpSession;
import java.util.HashMap;
import java.util.Map;

/**
 * @author  Joshua Long (josh@joshlong.com) 
 * 
 * This component encloses a panes. It decorates 
 * the enclosed panes. It also starts basic state 
 * management...
 *  
 */ 
public abstract class OutlookBar extends FoyerBaseComponent {

    public static final String OUTLOOK_BAR_COUNT = 
            "outlook_bar_count_id";
    public static final String AGGREGATE_ID = 
            "aggregate id string";

    private IScript script = null;

    protected void setupComponent(IRequestCycle cycle) {
        HttpSession session = cycle.getRequestContext().createSession();
        String selected_id = (String) session.getAttribute(
                OutlookLink.SELECTED_OUTLOOK_LINK_ID);
        if (selected_id == null) {
            selected_id = "$0__0";
        }
        log("trigger the seelcted pane is = " + selected_id);
         log("Initing Outlook bar");
        Integer value = (Integer)
cycle.getAttribute(OutlookBar.OUTLOOK_BAR_COUNT);
        if (null == value) {
            value = new Integer(0);
        } else {
            value = new Integer(value.intValue() + 1);
        }
        cycle.setAttribute(OutlookBar.OUTLOOK_BAR_COUNT, value);
        log("outlook_bar_count: " + value);

        if (script == null) {
            IScriptSource source = cycle.getEngine().getScriptSource();
            IResourceLocation location =
getSpecification().getLocation().getResourceLocation();
            IResourceLocation script_location =
location.getRelativeLocation("OutlookBar.script");
            script = source.getScript(script_location);
        }
        Body body = Body.get(cycle);
        Map symbols = new HashMap();
        symbols.put("selectedPaneId", selected_id);
        script.execute(cycle, body, symbols);
    }

    public abstract String getTitle();

    public abstract void setTitle(String title);


}




















// now for the outlook link 
package com.roartechnologies.ap.view.components.outlookbar;

import com.roartechnologies.ap.view.components.FoyerBaseComponent;
import org.apache.tapestry.*;
import org.apache.tapestry.engine.ILink;
import org.apache.tapestry.engine.IEngineService;


/**
 * @author  Joshua Long (josh@joshlong.com)
 *
 * This provides many services and renders 
 * an icon as well as its label.
 * You might imagine this where the Mail, 
 * or Calendar icons in Outlook are.
 * 
 * Yuck.. I know this could be prettier.
 */
public abstract class OutlookLink extends FoyerBaseComponent/*
implements IDirect */ {

    public static final String SELECTED_OUTLOOK_LINK_ID =
"SELECTED_OUTLOOK_LINK_ID_";

    public void trigger(IRequestCycle cycle) {
        IActionListener listener = getListener();
        Object[] params = cycle.getServiceParameters();
        for (int i = 0; i < params.length; i++) {
            log("Inside trigger(), the param is " + params[i]);
        }
        if (listener == null) {
            throw Tapestry.createRequiredParameterException(this,
"directLink");
        }
        listener.actionTriggered(this, cycle);
        cycle.getRequestContext().createSession().setAttribute(
        OutlookLink.SELECTED_OUTLOOK_LINK_ID, params[0]);
    }

    public boolean isStateful() {
        return false;
    }

    public void gotoPageAction(IRequestCycle cycle) {

        Object id = cycle.getAttribute(OutlookBar.AGGREGATE_ID);
        String pn = getPageName();
       
cycle.getRequestContext().createSession().setAttribute(OutlookLink.SELECTED_OUTLOOK_LINK_ID, id);
        log( "goto setting memory: page is ="+ getPageName() + "
selected id="+id);

        if (this.getPageName() != null) {
            log("goto Forwarding to a page") ;
            IPage page = cycle.getPage(getPageName());
            cycle.activate(page);
        } else {
            log("goto  invoking listener") ;
            getListener().actionTriggered(this, cycle);
        }
    }


    public abstract String getPageName();

    public abstract void setPageName(String page);

    public abstract String getDirectUrl();

    public abstract void setDirectUrl(String directUrl);

    public abstract IActionListener getListener();

    public abstract void setListener(IActionListener directLink);

    public abstract IAsset getImage();

    public abstract void setImage(IAsset asset);

    public abstract String getImageUrl();

    public abstract void setImageUrl(String imageUrl);

/*
    public abstract Object getParameters();

    public abstract void setParameters(Object parameters);
*/

    public abstract String getSelectedId();

    public abstract void setSelectedId(String selectedId);

    protected void setupComponent(IRequestCycle cycle) {
        if (cycle.isRewinding()) {
            return;
        }

        IAsset img = getImage();
        String url = img.buildURL(cycle);
        setImageUrl(url);

        Object id = cycle.getAttribute(OutlookBar.AGGREGATE_ID);
        setSelectedId((String) id);
      /* log("the id in link_setup() is " + id); */
        Object[] params = {id};
        IEngineService service =
cycle.getEngine().getService(Tapestry.DIRECT_SERVICE);
        ILink link = service.getLink(cycle, this, params);
        setDirectUrl(link.getURL());

        /**
         *   service =
cycle.getEngine().getService(Tapestry.ACTION_SERVICE );
        service.getLink(cycle, this, new Object[]{});

        /// Object id = cycle.getAttribute(OutlookBar.AGGREGATE_ID);
      //  String pn = getPageName();
    //  log("the page name for this link is: " + pn + "; and the
selectedId is " + id);
       //
cycle.getRequestContext().createSession().setAttribute(OutlookLink.SELECTED_OUTLOOK_LINK_ID, id);
               */
        if(isRestart())
            log( "This si a restart link  ") ;
   /*     if(getPageName() == null && getListener() == null)
            setRestart(true) ;*/
    }


    public abstract boolean isRestart()  ;
    public abstract void setRestart(boolean restart) ;

}








 /// the outlook panes 
package com.roartechnologies.ap.view.components.outlookbar;

import com.roartechnologies.ap.view.components.FoyerBaseComponent;
import org.apache.tapestry.IActionListener;
import org.apache.tapestry.IDirect;
import org.apache.tapestry.IRequestCycle;
import org.apache.tapestry.Tapestry;
import org.apache.tapestry.engine.IEngineService;
import org.apache.tapestry.engine.ILink;

/**
 * @author  Joshua Long (josh@joshlong.com)
 *
 * This component renders a pane. 
 * The pane in turn encloses the link
 * components.
 * 
 * A pane, in Outlook, is what you click 
 * on and which slides up or down to reveal 
 * other panes.
 * 
 *
 */
public abstract class OutlookPane extends FoyerBaseComponent implements
IDirect {
    public boolean isStateful() {
        return true;
    }
    public abstract IActionListener getListener();
    public abstract void setListener(IActionListener listener);
    public void trigger(IRequestCycle cycle) {
        log("Inside trigger on outlook pane");
        Object[] params = cycle.getServiceParameters();
        for (int i = 0; i < params.length; i++) {
            log("Inside trigger(), the param is " + params[i]);
        }
        cycle.getRequestContext().createSession().setAttribute(
            OutlookLink.SELECTED_OUTLOOK_LINK_ID, params[0]);
    }

    public static final String OUTLOOK_PANE_COUNT =
"outlook_pane_count";
    public abstract String getTitle();
    public abstract void setTitle(String title);

    protected void setupComponent(IRequestCycle cycle) {
        Integer bar_count = (Integer)
cycle.getAttribute(OutlookBar.OUTLOOK_BAR_COUNT);
        if (null == bar_count) {
            throw Tapestry.createRequiredParameterException(this,
              "You need to provide a outlook bar around this
component!");
        }
        log("\tInside of a pane, the bar count is " +
bar_count.intValue());
        Integer pane_count = (Integer)
cycle.getAttribute(OutlookPane.OUTLOOK_PANE_COUNT);
        if (null == pane_count) {
            pane_count = new Integer(0);
        } else {
            pane_count = new Integer(pane_count.intValue() + 1);
        }
        cycle.setAttribute(OutlookPane.OUTLOOK_PANE_COUNT, pane_count);
        log("\t\tinside a pane, the pane count is " + pane_count);
        String id = "$" + bar_count.intValue() + "__" +
pane_count.intValue();
        setPaneId(id);
        setShowjavaScript("showPanel('" + id + "');");
        cycle.setAttribute(OutlookBar.AGGREGATE_ID, id);
        Object[] params = {id};
        IEngineService service =
cycle.getEngine().getService(Tapestry.DIRECT_SERVICE);
        ILink link = service.getLink(cycle, this, params);
        String url = link.getURL();
        setDirectUrl(url);
        setShowjavaScript("window.location='" + url + "';");
    }

    public abstract String getDirectUrl();
    public abstract void setDirectUrl(String directUrl);
    public abstract String getShowjavaScript();
    public abstract void setShowjavaScript(String showjavaScript);
    public abstract String getPaneId();
    public abstract void setPaneId(String paneId);

}



















 /////// now we provide the various specifications / xml / assets 

// OutlookBar.script 

<?xml version="1.0"?>

<!DOCTYPE script PUBLIC
"-//Apache Software Foundation//Tapestry Script Specification 3.0//EN"
"http://jakarta.apache.org/tapestry/dtd/Script_3_0.dtd">

<script>
    <include-script resource-path="/outlook_bar.js"/>
    <input-symbol required="yes"  key="selectedPaneId"
class="java.lang.String" />
    <initialization>
       <![CDATA[
        showPanel("${selectedPaneId}") ;
          ]]>
    </initialization>
</script>






/////// the javascript 
//            "/outlook_bar.js"
//    I got the javascript/ css from 
	var g_currentPanel;

	function isBrowser(b,v) {
		browserOk = false;
		versionOk = false;

		browserOk = (navigator.appName.indexOf(b) != -1);
		if (v == 0) versionOk = true;
		else  versionOk = (v <= parseInt(navigator.appVersion));
		return browserOk && versionOk;
	}

	function showPanel(id) {
		var panel;
		if (isBrowser('Microsoft', 0))
			panel =
document.getElementById(id).parentNode.nextSibling.firstChild;
		else
			panel =
document.getElementById(id).parentNode.nextSibling.nextSibling.firstChild.nextSibling;
		if (g_currentPanel) g_currentPanel.className = 'groupPanelHidden';
		panel.className = 'groupPanel';
		g_currentPanel = panel;
	}





















/////////// the the css

.groupHeader, .groupHeaderOver, .groupHeaderClick {
    background-color: #CCCCCC;
    color: black;
    text-align: center;
    font-family: tahoma, arial;
    font-size: 10;
    border-left: 1px solid white;
    border-top: 1px solid white;
    height:10px;
}

.groupHeader {
    border-bottom: 1px solid #0074AD;
    padding: 3px;
}

.groupHeaderOver {
	border: 2px outset;
	padding: 2px;
}

.groupHeaderClick {
    border: 2px inset;
    padding: 2px;
}

/* the color for the background */
.groupPanel, .groupPanelHidden {
   /**  height: 100%;
      vertical-align: top;     border-top: 1px solid black;
   **/
    background-color: white;

    color: black;
    text-align: center;

}

.clippedRegion {
   overflow: auto;
}

.groupPanelHidden {
    display: none;
}

.outlookPanel {
 padding: 0px; margin: 0px;
}

.iconSection {
    margin-top: 0px;
    margin-bottom: 0px;
}

.icon {
    padding: 0px;
    width: 32px;
    height: 32px;
}

.iconOver {
    border-top: 1px solid #d6d3ce;
    border-left: 1px solid #d6d3ce;
    border-right: 1px solid black;
    border-bottom: 1px solid black;
    padding: 2px;
    width: 34px;
    height: 34px;
}

.iconClick {
    border-top: 1px solid black;
    border-left: 1px solid black;
    border-right: 1px solid #d6d3ce;
    border-bottom: 1px solid #d6d3ce;
    padding: 2px;
    width: 34px;
    height: 34px;
}

.iconLabel {
    padding: 1px;
    font-family: tahoma, arial;
    font-size: 11;
    cursor: default;
}


















//////////// the html /xml files 
// OutlookBar.html 



<table class="outlookPanel" height="100%" width="100%" cellpadding=0
border=0 cellspacing=0>
    <span jwcid="@RenderBody">
    [The various panels get rendered here. ]
    </span>
</table>
 

/////               OutlookBar.jwc
<!DOCTYPE component-specification PUBLIC
  "-//Apache Software Foundation//Tapestry Specification 3.0//EN"
  "http://jakarta.apache.org/tapestry/dtd/Tapestry_3_0.dtd">

<component-specification
   
class="com.roartechnologies.ap.view.components.outlookbar.OutlookBar"
allow-body="yes" allow-informal-parameters="yes" >

    <parameter name="title" direction="in" type="java.lang.String"  />

</component-specification> 






/////  OutlookLink.html 

<div class="iconSection" style="cursor: pointer">

 

<table width="100%"  cellpadding="0" cellspacing="0" border="0">
    <tr> <td height=5> &nbsp;</td></tr>
    <tr>
        <td align="center" valign="bottom" height=32>

                <span jwcid="@Conditional" condition="ognl:restart">
                  <a href="#" jwcid="@ServiceLink" service="restart">
                     <img jwcid="@Any" class="icon" width="32"
height="32" border="0" src="ognl:imageUrl"/>
                 </a>
                </span>
                
                <span jwcid="@Conditional" condition="ognl:!restart">
                 <a href="#" jwcid="@ActionLink"
listener="ognl:listeners.gotoPageAction">
                     <img jwcid="@Any" class="icon" width="32"
height="32" border="0" src="ognl:imageUrl"/>
                 </a>
                 </span>


        </td>
    </tr>
<tr>
<td align="center" height="20" valign="top">
    <div class="iconLabel">
        <span jwcid="@RenderBody">
            Render the ink here
        </span>
    </div>
</td>
</tr>  
</table>

</div>











//////             Outlook Link.jwc 

<!DOCTYPE component-specification PUBLIC
  "-//Apache Software Foundation//Tapestry Specification 3.0//EN"
  "http://jakarta.apache.org/tapestry/dtd/Tapestry_3_0.dtd">

<component-specification
class="com.roartechnologies.ap.view.components.outlookbar.OutlookLink"
allow-body="yes" allow-informal-parameters="yes" >
    <parameter  direction="auto"  name="listener"
default-value="listeners.gotoPageAction"
                type="org.apache.tapestry.IActionListener"    />
     <parameter name="image" required="yes" 
type="org.apache.tapestry.IAsset" direction="in" />
    <parameter name="restart" type="boolean" direction="in" />
    <parameter name="page" type="java.lang.String"
property-name="pageName" direction="in" />
    <property-specification name="imageUrl" type="java.lang.String" />
    <property-specification name="selectedId" 
type="java.lang.String"    />
    <property-specification  name="directUrl" type="java.lang.String" />
</component-specification>








 // OutlookPane.html 

 
<tr>
    <td id="ognl:paneId" onclick="ognl:showjavaScript"  jwcid="@Any"
                class="groupHeader"
                onmouseover="this.className='groupHeaderOver'"
                onmouseout="this.className='groupHeader'"
                onmousedown="this.className='groupHeaderClick'"
                onmouseup="this.className='groupHeaderOver'"
                style="cursor: pointer">
       <span jwcid="@Insert" value="ognl:title">
  	 title 
       </span>
     </td>
</tr>
<tr>
    <td class="groupPanelHidden">

        <div class="clippedRegion">
   
            <span jwcid="@RenderBody">
                Render the various links here
            </span>
     
        </div>

    </td>
</tr>
 










/// OutlookPane.jwc 

<!DOCTYPE component-specification PUBLIC
  "-//Apache Software Foundation//Tapestry Specification 3.0//EN"
  "http://jakarta.apache.org/tapestry/dtd/Tapestry_3_0.dtd">

<component-specification
   
class="com.roartechnologies.ap.view.components.outlookbar.OutlookPane"
allow-body="yes" allow-informal-parameters="yes" >

    <parameter name="title" direction="in" required="no" 
type="java.lang.String" />
      <property-specification name="showjavaScript"
type="java.lang.String" />
    <property-specification name="listener"
type="org.apache.tapestry.IActionListener"  />
    <property-specification name="directUrl" type="java.lang.String" /> 
    <property-specification name="paneId" type="java.lang.String" />

</component-specification>














---------------------------------------------------------------------
To unsubscribe, e-mail: tapestry-user-unsubscribe@jakarta.apache.org
For additional commands, e-mail: tapestry-user-help@jakarta.apache.org