2011-04-18 51 views
8

我们有一个Web应用程序,需要为每个主要客户提供不同的主题。最初的开发人员通过查看JavaScript中的URL并添加样式表来覆盖默认主题来实现此目的。多个“主题”的ClientBundle

这个问题的一个问题是,该网站有几秒钟的默认外观,然后突然交换正确的主题。另一个是它似乎浪费了很多带宽/时间。

我目前的想法是创建一个“默认”ClientBundle与我们的默认外观和感觉扩展该接口并覆盖每个条目(根据需要)与客户端的图像使用像@ImageResouce各种注释和指向不同的位置。

有没有人有过这样的经验?我预先考虑的一个问题是无法使用uibinder风格的标签,因为它们会静态指向特定的资源包。

任何想法?

+0

添加了一个例子... – helios 2011-04-18 22:11:03

回答

17

重写束

当然可以。

我已经用ClientBundles做了重写,并且正常工作。你必须做的一件事是继承属性的类型。举例:

BigBundle { 
    Nestedundle otherBundle(); 
    ImageResource otherImage(); 
    Styles css(); 
} 

然后你必须继承这种方式:

OtherBigBundle extends BigBundle { 
    OtherNestedBundle otherBundle(); // if you want to change it 
    ImageResource otherImage(); // of you want to change it 
    OtherStyles css(); // of you want to change it 
} 

OtherNestedBundle extends NestedBundleOtherStyles extends Styles

至少在CSS的:如果属性声明不使用子界面,他们将产生相同的CSS类名的样式,所有的都会混合使用。因此,与孩子的接口声明被覆盖的风格:)

灵活UIBinders

可以从外面包设置,如果你使用UiField(provided=true)注解使用。通过这种方式,您首先设置捆绑包,然后调用uibindler。假定它已经创建,它将使用资源字段。

递延结合

你可以使用GWT.runAsync加载只是正确的包。

一些示例

的用户界面。XML

<ui:with field='res' type='your.package.TheBundle'/> 

相应的类

@UiField(provided=true) TheBundle bundle; 

private void createTheThing() { 
    this.bundle = factory.createBundle(); 
    MyUiBindler binder = GWT.create(MyUiBindler.class); 
    this.panel = binder.createAndBindUi(this); 
    ... 
} 

一些捆绑接口

interface TheBundle extends ClientBundle { 
    @ImageResource("default.png") 
    ImageResource image1(); 

    @Source("default.css") 
    TheCss css(); 
} 

interface Theme1Bundle extends TheBundle { 
    @ImageResource("one.png") 
    ImageResource image1(); // type: imageresource is ok 

    @Source("one.css") 
    OneCss css(); // type: OneCss => use other compiled css class-names 

    interface OneCss extends TheCss { // inner-interface, just for fun 
    // don't need to declare each String method 
    } 
} 

如果不重写的东西它是捆绑工厂

确定

选项

1)只是共

if (...) { 
    return GWT.create(TheBundle.class); 
} else if (...) { 
    return GWT.create(Theme1Bundle.class); 
} 

2)runAsync(刚刚加载所需的部分...但在执行初始部分之后)

if (...) { 
    GWT.runAsync(new RunAsyncCallback() { 
     public void onSuccess() { 
     return GWT.create(TheBundle.class); 
     } 
     // please program the onFailure method 
    }); 
} else if (...) { 
    GWT.runAsync(new RunAsyncCallback() { 
     public void onSuccess() { 
     return GWT.create(Theme1Bundle.class); 
     } 
     // please program the onFailure method 
    }); 
} 

3)使用延迟 - 结合和发电机在编译时自动生成工厂基于批注包如@ThemeBundle("one")

此示例来自现实世界。我使用DynamicEntryPointWidgetFactory(简称DEPWidgetFactory)基于标识符字符串创建窗口小部件。每个小部件都是一个应用程序屏幕,每个主菜单都有它必须创建的widgetName。

在你的情况下,id将成为创建的主题。

重要提示:如果您使用runAsync,您不能在创建UI之前像创建示例代码那样创建资源包。您必须询问主题以及何时它已准备好(在回调中)将其传递给您的小部件构造函数,并且您的小部件可以将其分配给它的字段。

工厂接口:

public interface DynamicEntryPointWidgetFactory 
{ 
    public void buildWidget(String widgetName, AsyncCallback<Widget> callback); 
} 

Widget的注解产生:

@Target(ElementType.TYPE) 
public @interface EntryPointWidget 
{ 
    /** 
    * The name wich will be used to identify this widget. 
    */ 
    String value(); 
} 

模块配置:

它说:在工厂的实施将与此生成类(另一种选择是使用replace-with,但在我们的例子中,我们没有为每个语言环境或浏览器预定义选项,但是更具动态性)。

<generate-with class="com.dia.nexdia.services.gwt.rebind.entrypoint.DynamicEntryPointFactoryGenerator"> 
    <when-type-assignable class="com.dia.nexdia.services.gwt.client.entrypoint.DynamicEntryPointWidgetFactory" /> 
</generate-with> 

发电机:

public class DynamicEntryPointFactoryGenerator extends Generator { 
    @Override 
    public String generate(TreeLogger logger, GeneratorContext context, 
      String typeName) throws UnableToCompleteException { 
     PrintWriter pw = context.tryCreate(logger, 
       "x.services.gwt.client.entrypoint", 
       "DynamicEntryPointWidgetFactoryImpl"); 

     if (pw != null) { 
      // write package, imports, whatever 
      pw.append("package x.services.gwt.client.entrypoint;"); 
      pw.append("import x.services.gwt.client.entrypoint.DynamicEntryPointWidgetFactory;"); 
      pw.append("import com.google.gwt.core.client.GWT;"); 
      pw.append("import com.google.gwt.core.client.RunAsyncCallback;"); 
      pw.append("import com.google.gwt.user.client.rpc.AsyncCallback;"); 
      pw.append("import com.google.gwt.user.client.ui.Widget;"); 

      // the class 
      pw.append("public class DynamicEntryPointWidgetFactoryImpl implements DynamicEntryPointWidgetFactory {"); 

      // buildWidget method 
      pw.append(" public void buildWidget(String widgetName, final AsyncCallback<Widget> callback) {"); 

      // iterates over all the classes to find those with EntryPointWidget annotation 
      TypeOracle oracle = context.getTypeOracle(); 
      JPackage[] packages = oracle.getPackages(); 
      for (JPackage pack : packages) 
      { 
       JClassType[] classes = pack.getTypes(); 
       for (JClassType classtype : classes) 
       { 
        EntryPointWidget annotation = classtype.getAnnotation(EntryPointWidget.class); 
        if (annotation != null) 
        { 
         String fullName = classtype.getQualifiedSourceName(); 
         logger.log(TreeLogger.INFO, "Entry-point widget found: " + fullName); 

         pw.append("if (\"" + annotation.value() + "\".equals(widgetName)) {"); 
         pw.append(" GWT.runAsync(" + fullName + ".class, new RunAsyncCallback() {"); 
         pw.append("  public void onFailure(Throwable t) {"); 
         pw.append("   callback.onFailure(t);"); 
         pw.append("  }"); 
         pw.append("  public void onSuccess() {"); 
         pw.append("   callback.onSuccess(new " + fullName + "());"); 
         pw.append("  }"); 
         pw.append(" });"); 
         pw.append(" return;"); 
         pw.append("}"); 
        } 
       } 
      } 
      pw.append("callback.onFailure(new IllegalArgumentException(\"Widget '\" + widgetName + \"' not recognized.\"));"); 

      pw.append(" }"); 
      pw.append("}"); 

      context.commit(logger, pw);   
     } 

     // return the name of the generated class 
     return "x.services.gwt.client.entrypoint.DynamicEntryPointWidgetFactoryImpl"; 
    } 
+0

如何将选择3个工作?你在GWT xml配置文件中注册一个生成器? – benstpierre 2011-04-18 22:13:55

+1

没错。您可以指定哪个是BundleFactory接口的“生成器类”。该生成器类必须实现一个输出代码的方法。该代码写入“如果”。它可以使用一些GWT实用程序类来查找以某种方式标记的Bundle接口(如@ThemeBundle示例)。明天我可以发布一些示例代码,如果你喜欢。 – helios 2011-04-18 22:44:16

+0

与传统的css交换不会改变哪个css文件被加载立即reaload整个GUI?有没有办法达到同样的效果呢,还是我不得不将每种风格重新设置到新的捆绑包上。 – benstpierre 2011-05-02 00:22:29