So, a little late to jump in, but figured I'd add my $0.02 to this 
conversation.

I've been hard at work building a future-oriented declarative UI DSL.

Specifically, I extended the Java 8 JavaCC parser to include xml, json and 
css expression syntax.

This allows creation of UI's like the following toy code:

<app
  ref = "root"
  title = "Hi"
  data =
      {
          // The one button uses postIncrement++ so we start its count at 1
          one: 1,
          // The two button uses ++preIncrement, so we start its count at 0
          two: 0,
          text: ""
      }
  class = .{
      .cls{
        background-color: #011151;
       }
      .cls .btn {
        background-color: #010931;
        color: white;
      }
    }
  >
  <box
        size = ( 300 * (()->150 + 10 * $root.data.one) )
        align = center
  >
      <button ref="one" text="Button 1" class="btn button1" onClick=e-> {
        $one.setText("You clicked one " + $root.data.one++ + " times");
      } />

      <button ref="two" text="Button 2" class="btn button2" onClick=e-> {
        $two.setText("You clicked two " + ++$root.data.two + " times");
      } />

  </box>
  <box align = center>
      <button text="Close" onClick=System.exit(0) />
  </box>
</app>



It allows you to freely mix and match any form of AST you care about,
then a code generation subsystem allows you to define handled for any tag 
or attribute,
where you can turn any valid ast structure into whatever generated java 
syntax you want.

The really fun part?  It creates an interface, a base class and any number 
of implementations, with both GWT and JavaFX currently supported (Android 
support next; maybe iOS via J2ObjC some day).

For GWT, I am currently using Elemental 1 for low-level implementations, 
however, the abstractions are all designed to be completely orthogonal to 
low-level wiring.
Only the implementation classes know about GWT at all, so you can focus on 
business logic and correct abstractions, instead of making business logic 
dependent on UI implementation details.

The final bit I am working on before doing an official public release is 
the tag generator.
That is, a generator for the tag "define-tag", which will create not just 
the api, base and impl classes, but generate a code generator to then 
handle that tag in other UIs.
Best of all, the GWT implementation actually exports web components, so 
your defined "XApi declarative UI tag" actually becomes a web component 
bound to your java classes,
which can use DOM attributes as accessors  to primitives, and javascript 
for any kind of interop you want to do with the outside world.

Here is an example component I am using in my prototype:

<define-tag
    name = "Point"
    tagName = "wti-point"
    model =
        @Extend("HasAuthors")
        @Import("de.mocra.cy.shared.model.*")
        {
            lines: @Many // Ensures treatment of field as List-Type.
                IntTo.class.$generic(ModelText.class),
            title: String.class,
            hasLinks: public boolean hasLinks(){
                return 
getLines().hasMatch(t->t.allText().hasMatch(TextNode::isLink));
            }
        }
    api = [
        public String getTitle() {
            return $model.getTitle();
        }
        ,
        public $Self setTitle(String text) {
            $model.setTitle(text);
            return this;
        }
    ]
    impl =
    @Import({
        "de.mocra.cy.shared.ast.WtiParser",
        "de.mocra.cy.shared.css.HasWtiStyle",
        "de.mocra.cy.shared.css.WtiStyle"
    })
    [
        private HasWtiStyle resources;, // ugh;, semicolon comma on purpose. , 
is for json array parser
                                        // Either make it a statement w/ 
semi-colon, or use (parens)
        public HasWtiStyle getResources() {
            return resources;
        },
        public WtiStyle getStyle() {
            return resources.css();
        },
        public $Self ui() {
            return this;
        }
    ]

    ui =
        <box>
            <if notNull=$model.title>
                <wti-title ref="title">$model::title</wti-title>
            </if>
            <for allOf=$model.lines as=text>
                // setting the model directly is the cue for the generator
                // that this is going to be an ElementWithModel that has a 
.fromModel method.
                <wti-text model=text style=getResources() />
            </for>
        </box>

/define-tag>


Finally, this framework is good for more than just UIs...  I also use it to 
generate all sorts of other repetitive tasks;
for example, TriFunction or QuadFunction, etc...  The java sdk functional 
interfaces are pretty sparse,
so I've taken to generating my own extrapolations of N-ary functional 
interfaces (by default scaling up to 5-in, 5-out, with potential to 
dynamically generate higher arities if needed for method references.

package xapi.fu.out;
@Generate(
    in = {
        <var name = "max"
            default = 5 />,
        <var name = "types"
            default = ["Type", "Int", "Long", "Double", "Bool"] />
    },
    out = {
        <loop
            from = 1
            to = $max
            var = "size"
        >
            <generateInterface
                var = {
                    typeParams :
                        $range(1, $size, $i->`O$i`),
                    wrappedParams :
                        $range(1, $size, $i->`Out1<O$i>`)
                }
                template =
                    @Import({
                        "xapi.fu.HasOutput",
                        "xapi.fu.Rethrowable",
                        "xapi.fu.Lambda"
                    })
                    public interface Out$size <$typeParams>
                                extends HasOutput, Rethrowable, Lambda {

                     Immutable$size <$wrappedParams> outAll();

                     @unfold(from = 1, to = $size, var = "n")
                     default O$n out$n(){
                         return out$nProvider().out1();
                     }

                     @unfold(from = 1, to = $size, var = "n")
                     default Out1<O$n> out$nProvider(){
                         return outAll().out$n();
                     }

                     @unfold(from = 1, to = $size, var = "n")
                     default Out$size<$typeParams> read$n(In1<O$n> callback){
                         callback.in(out$n());
                         return this;
                     }

                     @unfold(from = 1, to = $size, var = "n")
                     @var(
                         name = "outParams",
                         value = $range(1, $size, $p ->
                             $p == $n ? "To" : `O$p`)
                     )
                     default <To> Out$size<$outParams> mapped$n(In1Out1<O$n, 
To> mapper){
                         return Out.out3(
                           $range(1, $size, $p ->
                               $p == $n ? 
mapper.supplyDeferred(out$pProvider()) : out$pProvider()
                           )
                         );
                     }

                     @unfold(from = 1, to = $size, var = "n")
                     default <To> Out$size<$typeParams> spy$n(In1<O$n> 
callback){
                         return
                           $if($size == 1, $print(()->{
                               O1 out = out1();
                               callback.in(out);
                               return out;
                           }))
                           .$else(
                               Out.out$size(
                               $range(1, $size, $p ->
                                   $p == $n ? out$pProvider().spy1(callback) : 
out$pProvider()
                               )
                           )
                         );
                     }


                }
            /generateInterface>

        </loop>,

        <loop
            from = 1
            to = 3
            var = "size">
            <var name = "asPrimitive"
                value = {
                    Type:"O$n",
                    Int:"int",
                    Long:"long",
                    Double:"double",
                    Bool:"boolean"
                } />,
            <var name = "asObject"
                value = {
                    Type:"O$n",
                    Int: "Integer",
                    Long: "Long",
                    Double: "Double",
                    Bool: "Boolean"
                } />
        </loop>
    })
public class Out {
}




So, it's definitely a work in progress, but I am hoping that the community 
finds value in it, and it gains more than one maintainer going forward. :-)

-- 
You received this message because you are subscribed to the Google Groups "GWT 
Contributors" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/google-web-toolkit-contributors/d7da6526-caba-4f28-a43e-33676257a3bf%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to