sitemesh3 feature request

307 views
Skip to first unread message

fabrice....@gmail.com

unread,
Feb 17, 2014, 9:24:15 AM2/17/14
to sitemes...@googlegroups.com
Hello,

Sitemesh3 introduce a new feature that I consider very useful :  to be able to build offline website with sitemesh

But in sitemesh3 there is a feature I used heavily on sitemesh2 that is missing : the ability to include some code fragment (from an other file) in a page :

In sitemesh2, inside a decorator, I was regularly using the page:applyDecorator   tag  :

<page:applyDecorator page="menubar.html" name="panel" encoding="utf-8" />

This will insert an html code fragment from the file "menubar.html"  and decorate it with the decorator "panel"
Here the "menubar.html" path is relative to the current file being decorated (= in the same folder)

Would it be possible to do the same in sitemesh3 :

I would like to do something  quite similar to the decorate tag,  
<sitemesh:decorate decorator='/mydecorator' title='foo' cheese='bar'>blah</sitemesh:decorate>

But with the content not in the body of the tag (as here for "blah")  but from an other file :

<sitemesh:include src="menubar.html" decorator="panel" />      

would it be possible ?

Regards,

--fabrice





fabrice....@gmail.com

unread,
Aug 6, 2014, 12:11:46 PM8/6/14
to sitemes...@googlegroups.com
I'v tried to do it myself, it works, but I have still a problem : included file seems not to be parsed by site mesh 

Here is my code :

package org.sitemesh.content.tagrules.html;

import java.io.File;
import java.nio.file.Paths;
import java.nio.CharBuffer;
import org.sitemesh.SiteMeshContext;
import org.sitemesh.content.memory.InMemoryContent;
import org.sitemesh.content.ContentProperty;
import org.sitemesh.content.Content;
import org.sitemesh.tagprocessor.Tag;
import org.sitemesh.tagprocessor.BasicBlockRule;
import org.sitemesh.offline.directory.Directory;
import org.sitemesh.offline.directory.FileSystemDirectory;


import java.io.IOException;

/**
 * Rule that applies decorators to an external file and insert decorated content in the current page
 *
 *
 * <h3>Example</h3>
 *
 * {@code <sitemesh:decorate decorator='/mydecorator' srcfile='/fragment.html'/>}
 *
 * <p>This will apply the decorator named <code>/mydecorator</code>, on the file <code>fragment.html</code>
 * and insert the result in the current page</p>
 * 
 * @author Fabrice Gaillard
 */
public class SiteMeshIncludeRule extends BasicBlockRule<SiteMeshIncludeRule.Holder> {

    static class Holder {
        public final Content content = new InMemoryContent();
        public String decoratorName;
    }

    private final SiteMeshContext siteMeshContext;

    public SiteMeshIncludeRule(SiteMeshContext siteMeshContext) {
        this.siteMeshContext = siteMeshContext;
    }

    @Override
    protected Holder processStart(Tag tag) throws IOException {
        tagProcessorContext.pushBuffer();

        Holder holder = new Holder();
        for (int i = 0, count = tag.getAttributeCount(); i < count; i++) {
            String name = tag.getAttributeName(i);
            String value = tag.getAttributeValue(i);
            if (name.equals("decorator")) {
                holder.decoratorName = value;
            }
            if (name.equals("srcfile")) {
                //
                // try to incude the file referenced in srcfile
                // we need to figure the path, relative to the current dir
                //
            //String curpage = siteMeshContext.getPath();
                String curpath = Paths.get("").toAbsolutePath().toString();
                Directory curdir = new FileSystemDirectory(new File(curpath));
                CharBuffer input = curdir.load(value);
                //
                // works, but it seems the content is not processed (body not extracted)
                //
                holder.content.getData().setValue(input);
                holder.content.getExtractedProperties().getChild("body").setValue(input);
            }
        }

        return holder;
    }

    @Override
    protected void processEnd(Tag tag, Holder holder) throws IOException {
        CharSequence defaultContents = tagProcessorContext.currentBufferContents();
        tagProcessorContext.popBuffer();

        Content decorated = siteMeshContext.decorate(holder.decoratorName, holder.content);
        if (decorated != null) {
            // TODO: Use a 'default' property
            decorated.getExtractedProperties().getChild("body").writeValueTo(tagProcessorContext.currentBuffer());
        }
    }

}


and here is an example decorator (using bootstrap)

<!DOCTYPE html>
<html lang="fr">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <!-- Bootstrap -->
    <link href="css/bootstrap.min.css" rel="stylesheet">
    <title><sitemesh:write property='title'/></title>
    <sitemesh:write property='head'/>
  </head>
  <body>
    <div class="container">
      <sitemesh:include decorator="/decorators/portlet.html" srcfile="/src/menubar.fr.inc.html" />

      <div class="row">
        <div class="col-md-8">
          <!-- Main content -->
          <div class="well">
            <sitemesh:write property='body'/>
          </div>
        </div>
        <div class="col-md-4 hidden-xs hidden-sm">
          <div class="well center-block">
            <img src="images/300x250.gif"/>
            <p></p>
            <img src="images/300x250.gif"/>
          </div>
        </div>
      </div>
      

    </div> <!-- /container -->

    <!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
    <!-- Include all compiled plugins (below), or include individual files as needed -->
    <script src="js/bootstrap.min.js"></script>
  </body>
</html>


The idea is to include contextual components (here a menubar), inside the mail decorator.

the menubar code fragment is :

<nav class="navbar navbar-default" role="navigation">
  <div class="container-fluid">
    <!-- Brand and toggle get grouped for better mobile display -->
    <div class="navbar-header">
      <button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
        <span class="sr-only">Toggle navigation</span>
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
      </button>
      <a class="navbar-brand" href="/index.fr.html">SiteName</a>
    </div>

    <!-- Collect the nav links, forms, and other content for toggling -->
    <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
      <ul class="nav navbar-nav">
              <li><a href="/CP/arts/index.fr.html">Arts</a></li>
              <li><a href="/CP/culture/index.fr.html">Culture</a></li>
              <li><a href="/CP/internet/index.fr.html">Internet</a></li>
              <li><a href="/CP/medias/index.fr.html">Media</a></li>
      </ul>
      <form class="navbar-form navbar-right" role="search">
        <div class="form-group">
          <input type="text" class="form-control" placeholder="Search">
        </div>
        <button type="submit" class="btn btn-default">Submit</button>
      </form>
    </div><!-- /.navbar-collapse -->
  </div><!-- /.container-fluid -->
</nav>



Can anybody correct / improve my code 

Regards,

--Fabrice


Reply all
Reply to author
Forward
0 new messages