Changeset 5482


Ignore:
Timestamp:
Nov 10, 2010, 12:16:51 PM (12 years ago)
Author:
Nicklas Nordborg
Message:

References #1545: Add extension points to edit pages

Adds support for extensions to the TabControl taglib. The TabAction interface is used to define extra tabs. Two factories have been implemented:

  • FixedTabFactory: Mainly useful for testing
  • IncludeContentTabFactory: The content of the tab is generated from an included resource (eg. a JSP script or servlet)


Extension points have so far only been implemented on the "Edit sample" dialog, but more will be added later.

Some more "side-effects" from this change:

  • Added support for 'class' attribute to TabControl and Tab taglibs.
  • Added 'onActivate' callback to Tab taglib if a tab need to perform some action when it is activated.
  • Log a warning message when trying to use an undefined extension point (I know this happens for for some toolbars).
  • Add support for context-relative paths to the PathSetter/PathConverter annotation.
  • Removed some obsolete documentation for the TabControl taglib.
Location:
trunk
Files:
7 added
5 deleted
10 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/clients/web/net/sf/basedb/clients/web/extensions/ExtensionsControl.java

    r5384 r5482  
    3232
    3333import net.sf.basedb.clients.web.extensions.service.Services;
     34import net.sf.basedb.clients.web.extensions.tabcontrol.TabControlUtil;
    3435import net.sf.basedb.clients.web.extensions.toolbar.ToolbarUtil;
    3536import net.sf.basedb.clients.web.servlet.ExtensionsServlet;
     
    144145    registry = new Registry();
    145146   
    146     // Toolbar extensions are added programmatically
     147    // Register some extension points programmatically. This
    147148    // must be done before scanning files otherwise it is not
    148     // possible to register extension for the toolbars
    149     ToolbarUtil.registerExtensionPoints(registry);
     149    // possible to register extensions for for them
     150    ToolbarUtil.registerExtensionPoints(registry);  // Toolbars
     151    TabControlUtil.registerExtensionPoints(registry); // TabControls
    150152   
    151153    // Load settings
  • trunk/src/clients/web/net/sf/basedb/clients/web/taglib/tab/Tab.java

    r4889 r5482  
    2626import javax.servlet.jsp.JspTagException;
    2727import javax.servlet.jsp.tagext.BodyTagSupport;
     28
     29import net.sf.basedb.clients.web.extensions.tabcontrol.TabAction;
    2830
    2931/**
     
    3436   <t:tab
    3537      id=...
     38      clazz=...
    3639      style=...
    3740      title=...
    3841      tooltip=...
    3942      validate=...
     43      activate=...
    4044      visible=true|false
    4145      helpid=...
     
    6670  </tr>
    6771  <tr>
     72    <td>clazz</td>
     73    <td>button</td>
     74    <td>no</td>
     75    <td>
     76      The value if this attribute goes directly into the standard HTML
     77      <code>class</code> attribute. This allows you to apply different styles
     78      to different tables.
     79    </td>
     80  </tr>
     81  <tr>
    6882    <td>style</td>
    6983    <td>-</td>
     
    96110    FALSE the switch will not be made. You may, for example, use this attribute
    97111    to validate input data in a form.
     112    </td>
     113  </tr>
     114  <tr>
     115    <td>activate</td>
     116    <td>-</td>
     117    <td>no</td>
     118    <td>An optional JavaScript expression that will be executed when the switches
     119      to this tab.
    98120    </td>
    99121  </tr>
     
    122144public class Tab
    123145  extends BodyTagSupport
     146  implements TabAction
    124147{
    125148
     
    135158 
    136159  /**
     160    Optional <code>class</code> attribute.
     161    @since 2.17
     162  */
     163  private String clazz;
     164 
     165  /**
    137166    Optional <code>style</code> attribute
    138167  */
     
    153182  */
    154183  private String validate = null;
     184
     185  /**
     186    A JavaScript method that is invoked when activating the tab.
     187  */
     188  private String activate = null;
    155189
    156190  /**
     
    168202    Taglib initialization methods
    169203  */
     204  /**
     205    @since 2.17
     206  */
     207  public void setClazz(String clazz)
     208  {
     209    this.clazz = clazz;
     210  }
     211  /**
     212    @since 2.17
     213  */
     214  @Override
     215  public String getClazz()
     216  {
     217    return clazz;
     218  }
     219 
    170220  public void setStyle(String style)
    171221  {
    172222    this.style = style;
    173223  }
     224  @Override
    174225  public String getStyle()
    175226  {
     
    181232    this.title = title;
    182233  }
     234  @Override
    183235  public String getTitle()
    184236  {
     
    190242    this.tooltip = tooltip;
    191243  }
     244  @Override
    192245  public String getTooltip()
    193246  {
     
    199252    this.validate = validate;
    200253  }
    201   public String getValidate()
     254  @Override
     255  public String getOnValidate()
    202256  {
    203257    return validate;
    204258  }
    205  
     259
     260  /**
     261    @since 2.17
     262  */
     263  public void setActivate(String activate)
     264  {
     265    this.activate = activate;
     266  }
     267  /**
     268    @since 2.17
     269  */
     270  @Override
     271  public String getOnActivate()
     272  {
     273    return activate;
     274  }
     275
    206276  public void setVisible(boolean visible)
    207277  {
    208278    this.visible = visible;
    209279  }
     280  @Override
    210281  public boolean isVisible()
    211282  {
     
    235306    throws JspException
    236307  {
    237     if (isVisible()) tc.addTab(this, bodyContent != null ? bodyContent.getString() : null);
     308    if (isVisible()) tc.addTab(this);
    238309    return EVAL_PAGE;
    239310  }
     311
     312  /*
     313    From the TabAction interface
     314    ----------------------------
     315  */
     316  @Override
     317  public String getHelpId()
     318  {
     319    return helpid;
     320  }
     321
     322  @Override
     323  public String getContent()
     324  {
     325    return bodyContent != null ? bodyContent.getString() : null;
     326  }
     327  // -----------------------------
    240328}
    241329
  • trunk/src/clients/web/net/sf/basedb/clients/web/taglib/tab/TabControl.java

    r5322 r5482  
    2626import javax.servlet.jsp.JspTagException;
    2727import javax.servlet.jsp.tagext.TagSupport;
     28
     29import net.sf.basedb.clients.web.extensions.tabcontrol.TabAction;
     30import net.sf.basedb.util.extensions.ExtensionsInvoker;
     31import net.sf.basedb.util.extensions.Renderer;
    2832
    2933/**
     
    3539  <pre>
    3640   &lt;t:tabcontrol
    37       id=....
     41      id=...
     42      clazz=...
    3843      style=...
    3944      contentstyle=...
     
    4449      autoheight=true|false
    4550      notabs=true|false
     51      extensions=...
    4652   &gt;
    4753</pre>
     
    7076  </tr>
    7177  <tr>
     78    <td>clazz</td>
     79    <td>button</td>
     80    <td>no</td>
     81    <td>
     82      The value if this attribute goes directly into the standard HTML
     83      <code>class</code> attribute. This allows you to apply different styles
     84      to different tables.
     85    </td>
     86  </tr>
     87  <tr>
    7288    <td>style</td>
    7389    <td>-</td>
     
    143159      If the tabcontrol should display tabs or not. If false the tab control will
    144160      not output any HTML except the contents of the active tab.
     161    </td>
     162  </tr>
     163  <tr>
     164    <td>extensions</td>
     165    <td>-</td>
     166    <td>no</td>
     167    <td>
     168      An {@link ExtensionsInvoker} for {@link TabAction} extensions. All
     169      actions will be rendered by this tabcontrol after all the
     170      normally defined tags have been rendered. Since BASE 2.17.
    145171    </td>
    146172  </tr>
     
    153179public class TabControl
    154180  extends TagSupport
     181  implements Renderer<TabAction>
    155182{
    156183  /**
     
    160187
    161188  /**
     189    Optional <code>class</code> attribute.
     190    @since 2.17
     191  */
     192  private String clazz;
     193
     194  /**
    162195    Optional <code>style</code> attribute
    163196  */
     
    203236  */
    204237  private boolean noTabs = false;
     238 
     239  private ExtensionsInvoker<TabAction> extensions;
    205240 
    206241  /**
     
    242277    Taglib initialization methods
    243278  */
     279  /**
     280    @since 2.17
     281  */
     282  public void setClazz(String clazz)
     283  {
     284    this.clazz = clazz;
     285  }
     286  /**
     287    @since 2.17
     288  */
     289  public String getClazz()
     290  {
     291    return clazz;
     292  }
     293
    244294  public void setStyle(String style)
    245295  {
     
    309359  }
    310360 
     361  public void setExtensions(ExtensionsInvoker<TabAction> extensions)
     362  {
     363    this.extensions = extensions;
     364  }
     365
     366 
    311367  public void setRemember(boolean remember)
    312368  {
     
    314370  }
    315371 
    316   void addTab(Tab tab, String tabcontent)
     372  void addTab(TabAction tab)
    317373  {
    318374    numTabs++;
     
    325381    {
    326382      String className = position == BOTTOM ? "tab_bottom" : "tab";
     383      if (tab.getClazz() != null) className += " " + tab.getClazz();
    327384 
    328385      tabs.append("<td id=\"").append(getId()).append(".").append(tab.getId()).append("\"");
     
    336393      script.append("TabControl.initTab('");
    337394      script.append(getId()).append("', '").append(tab.getId()).append("', ");
    338       script.append(tab.getValidate() == null ? "null" : "'"+tab.getValidate()+"'");
    339       script.append(", ").append(tab.getHelpid() == null ? "null" : "'" + tab.getHelpid() + "'");
     395      script.append(tab.getOnValidate() == null ? "null, " : "'" + tab.getOnValidate() + "', ");
     396      script.append(tab.getOnActivate() == null ? "null, " : "'" + tab.getOnActivate() + "', ");
     397      script.append(tab.getHelpId() == null ? "null" : "'" + tab.getHelpId() + "'");
    340398      script.append(");\n");
    341399    }
    342400   
    343     if (tabcontent != null)
     401    String tabContent = tab.getContent();
     402    if (tabContent != null)
    344403    {
    345404      content.append("<div id=\"").append(getId()).append(".").append(tab.getId()).append(".content\"");
    346405      if (!noTabs) content.append(" style=\"display:none;");
    347406      content.append("\">");
    348       content.append(tabcontent);
     407      content.append(tabContent);
    349408      content.append("</div>\n");
    350409    }
     
    360419
    361420    if (noTabs) return EVAL_BODY_INCLUDE;
     421    String className = position == BOTTOM ? "tabcontrol_bottom" : "tabcontrol";
     422    if (getClazz() != null) className += " " + getClazz();
    362423    StringBuilder sb = new StringBuilder();
    363     sb.append("<table class=\"").append(position == BOTTOM ? "tabcontrol_bottom" : "tabcontrol").append("\"");
     424    sb.append("<table class=\"").append(className).append("\"");
    364425    sb.append(" id=\"").append(getId()).append("\"");
    365426    sb.append(" border=0 cellspacing=0 cellpadding=0");
     
    387448    throws JspException
    388449  {
     450    if (extensions != null) extensions.render(this);
     451   
    389452    StringBuilder sb = new StringBuilder();
    390453    if (noTabs)
     
    418481      sb.append("<script language=\"JavaScript\">\n");
    419482      sb.append("Main.onLoad(function() {\n");
     483      sb.append(script);
    420484      sb.append("\tvar switchFunction = TabControl.setActiveTab;\n");
    421485      sb.append("\tif (typeof ").append(getSwitch()).append(" != 'undefined') switchFunction = ").append(getSwitch()).append(";\n");
     
    423487      sb.append(remember ? "1" : "0").append(", switchFunction, ");
    424488      sb.append(autoAdjustHeight ? "true" : "false").append(");\n");
    425       sb.append(script);
    426489      sb.append("});\n");
    427490      sb.append("</script>\n");
     
    439502    return EVAL_PAGE;
    440503  }
     504 
     505  /*
     506    From the Renderer interface
     507    ---------------------------
     508  */
     509  @Override
     510  public void render(TabAction action)
     511  {
     512    addTab(action);
     513  }
     514  // ---------------------------
     515 
    441516}
    442517
  • trunk/src/core/net/sf/basedb/util/extensions/Registry.java

    r5014 r5482  
    538538      if (rep == null || !filter.isEnabled(rep))
    539539      {
     540        if (rep == null)
     541        {
     542          // Trying to use an unedefined extension point should log a warning
     543          log.warn("Undefined extension point: " + id, new RuntimeException());
     544        }
    540545        /* #### CONTINUE-STATEMENT #### */
    541546        continue;
  • trunk/src/core/net/sf/basedb/util/extensions/xml/PathConverter.java

    r4515 r5482  
    2626/**
    2727  A value converter that can be used on all setter methods
    28   that has been annotated with the {@link PathSetter}
    29   annotation. The values are converted using the following rules:
     28  that has been annotated with the {@link PathSetter} and
     29  {@link PathType} annotations. The values are converted using the
     30  following rules:
    3031 
    3132  <ul>
     
    3536    the current extension is added, for example,
    3637    <code>~/images/myimage.png --&gt; /base2/extensions/my-extensions.jar/images/myimage.png</code>
     38  <li>If the path type is {@link PathType#CONTEXT_RELATIVE} the context-path is
     39    removed from the final path. Eg. <code>/base2/images/copy.gif --&gt; /images/copy.gif</code>
    3740  </ul>
    3841
     
    5659  private String root;
    5760  private String home;
    58  
    5961  /**
    6062    Create a new empty path converter. Use {@link #setRoot(String)}
     
    9294      in = home + in.substring(1);
    9395    }
     96    // Remove the 'root' part if the path should be context relative
     97    PathType pathType = method.getAnnotation(PathSetter.class).pathType();
     98    if (pathType == PathType.CONTEXT_RELATIVE)
     99    {
     100      if (in.startsWith(root)) in = in.substring(root.length());
     101    }
    94102    return in;   
    95103  }
    96 
    97104  // ---------------------------------------
    98105
  • trunk/src/core/net/sf/basedb/util/extensions/xml/PathSetter.java

    r4515 r5482  
    4343@Retention(RetentionPolicy.RUNTIME)
    4444public @interface PathSetter
    45 {}
     45{
     46  /**
     47    The type of path that should be generated. The default is
     48    to generate absolute paths.
     49    @since 2.17
     50  */
     51  public PathType pathType() default PathType.ABSOLUTE;
     52}
  • trunk/www/WEB-INF/tab.tld

    r4889 r5482  
    5353    </attribute>
    5454    <attribute>
     55      <name>clazz</name>
     56      <required>false</required>
     57      <rtexprvalue>true</rtexprvalue>
     58    </attribute>
     59    <attribute>
    5560      <name>style</name>
    5661      <required>false</required>
     
    102107      <rtexprvalue>true</rtexprvalue>
    103108    </attribute>
     109    <attribute>
     110      <name>extensions</name>
     111      <required>false</required>
     112      <rtexprvalue>true</rtexprvalue>
     113    </attribute>
    104114  </tag>
    105115
     
    110120      <name>id</name>
    111121      <required>true</required>
     122      <rtexprvalue>true</rtexprvalue>
     123    </attribute>
     124    <attribute>
     125      <name>clazz</name>
     126      <required>false</required>
    112127      <rtexprvalue>true</rtexprvalue>
    113128    </attribute>
     
    133148    </attribute>
    134149    <attribute>
     150      <name>activate</name>
     151      <required>false</required>
     152      <rtexprvalue>true</rtexprvalue>
     153    </attribute>
     154    <attribute>
    135155      <name>visible</name>
    136156      <required>false</required>
  • trunk/www/admin/extensions/tree.jsp

    r5426 r5482  
    117117    var byExtPoint = JoustMenu.addMenuItem(-1, 'Root', 'By extension point', 'rootOnClick()', '', '');
    118118    var toolbars = JoustMenu.addChildItem(byExtPoint, 'Folder', 'Toolbars');
     119    var editDialogs = JoustMenu.addChildItem(byExtPoint, 'Folder', 'Edit dialogs');
    119120    var ep;
    120121    var ext;
     
    125126    {
    126127      ExtensionPoint ep = extensionPoints.next();
    127       String parent = ep.getId().startsWith("net.sf.basedb.clients.web.toolbar") ?
    128           "toolbars" : "byExtPoint";
     128      String id = ep.getId();
     129      String parent = "byExtPoint";
     130      if (id.startsWith("net.sf.basedb.clients.web.toolbar.")) parent = "toolbars";
     131      if (id.startsWith("net.sf.basedb.clients.web.tabcontrol.edit.")) parent = "editDialogs";
    129132      %>
    130133      <%=getJoustExtensionPoint(parent, ec, ep)%>
  • trunk/www/biomaterials/samples/edit_sample.jsp

    r5474 r5482  
    5454  import="net.sf.basedb.clients.web.formatter.FormatterFactory"
    5555  import="net.sf.basedb.clients.web.formatter.FormatterSettings"
     56  import="net.sf.basedb.core.plugin.GuiContext"
     57  import="net.sf.basedb.clients.web.extensions.ExtensionsControl"
     58  import="net.sf.basedb.clients.web.extensions.JspContext"
     59  import="net.sf.basedb.clients.web.extensions.tabcontrol.TabControlUtil"
     60  import="net.sf.basedb.util.extensions.ExtensionsInvoker"
    5661  import="java.util.List"
    5762  import="java.util.Set"
     
    6166<%@ taglib prefix="base" uri="/WEB-INF/base.tld" %>
    6267<%@ taglib prefix="t" uri="/WEB-INF/tab.tld" %>
     68<%@ taglib prefix="ext" uri="/WEB-INF/extensions.tld" %>
    6369<%
    6470final Item itemType = Item.SAMPLE;
     
    202208  String jsDateFormat = HTML.javaScriptEncode(dateFormat);
    203209  String htmlDateFormat = HTML.encodeTags(dateFormat);
     210  JspContext jspContext = ExtensionsControl.createContext(dc, pageContext, GuiContext.item(itemType), sample);
     211  ExtensionsInvoker invoker = TabControlUtil.useExtensions(jspContext);
    204212  %>
    205 
    206213  <base:page type="popup" title="<%=title%>">
    207214  <base:head scripts="tabcontrol.js,annotations.js,linkitems.js" styles="tabcontrol.css">
     215    <ext:scripts context="<%=jspContext%>" />
     216    <ext:stylesheets context="<%=jspContext%>" />
    208217    <script language="JavaScript">
    209218    // Validate the "Sample" tab
     
    567576    <h3 class="docked"><%=title%> <base:help tabcontrol="settings" /></h3>
    568577    <t:tabcontrol id="settings" contentstyle="<%="height: "+(int)(scale*370)+"px;"%>"
    569       position="bottom"  remember="<%=sample != null%>" switch="switchTab">
     578      position="bottom"  remember="<%=sample != null%>" switch="switchTab"
     579      extensions="<%=invoker%>">
    570580    <t:tab id="info" title="Sample" validate="validateSample()" helpid="sample.edit">
    571581      <table class="form" cellspacing=0>
  • trunk/www/include/scripts/tabcontrol.js

    r5091 r5482  
    118118      tabControl.activeContent = content;
    119119    }
     120    if (tab.activate) eval(tab.activate);
    120121    TabControl.rememberActiveTab(theWindow, tabControlId, tabId);
    121122    return true;
     
    214215    @param tabControlId The ID attribute of the main tabcontrol
    215216    @param tabId The ID attribute of the tab
    216     @param validate The function that validates the tab
     217    @param validate The function that validates the tab (optional)
     218    @param activate The funcation that is executed when the tab is activated (optional)
    217219    @param helpId The help id for the tab
    218220  */
    219   this.initTab = function(tabControlId, tabId, validate, helpId)
     221  this.initTab = function(tabControlId, tabId, validate, activate, helpId)
    220222  {
    221223    var realTabId = tabControlId+'.'+tabId;
     
    224226    {
    225227      if (validate) tab.validate = validate;
     228      if (activate) tab.activate = activate;
    226229      if (helpId) tab.helpId = helpId;
    227230    }
Note: See TracChangeset for help on using the changeset viewer.