Im looking to load a different user interface in my GWT application if the user is accessing from a mobile web browser or desktop web browser. I was wondering how I would edit my Application.gwt.xml file change which entry point class is loaded based on the the form factor. I thought it might be something along these lines but i'm kind of just hacking so I was wondering if anyone had any ideas?
<entry-point class="webapp.client.WebAppEntryPoint">
<when-property-is name="formfactor" value="desktop"/>
</entry-point>
<entry-point class="webapp.client.MobileAppEntryPoint">
<when-property-is name="formfactor" value="mobile"/>
</entry-point>
Cheers.
Its almost as easy as you describe it -- that is, once you have worked out the formfactor property and how to pick a value for it.
It turns out that when you create an entrypoint and declare it in your module, the compiler uses GWT.create to actually make an instance of it. This leaves it subject to the rebind rules declared in your module. So if both WebAppEntryPoint and MobileAppEntryPoint inherit from some common superclass, you can declare that entrypoint in the module, and a slight varient on the rules you made to trigger them to be selected:
<entry-point class="webapp.client.AbstractAppEntryPoint" />
<replace-with class="webapp.client.WebAppEntryPoint">
<when-type-is class="webapp.client.AbstractAppEntryPoint" />
<when-property-is name="formfactor" value="desktop"/>
</entry-point>
<replace-with class="webapp.client.MobileAppEntryPoint">
<when-type-is class="webapp.client.AbstractAppEntryPoint" />
<when-property-is name="formfactor" value="mobile"/>
</entry-point>
These rules state: "When GWT tries to start the app, use AbstractEntryPoint (which implements EntryPoint) to do so. When someone invokes GWT.create(AbstractEntryPoint) and formfactor is desktop, give them a WebAppEntryPoint instance. When someone invokes GWT.create(AbstractEntryPoint) and formfactor is mobil, give them a MobileAppEntryPoint instance.
This then leaves the hard part - how do you build the formfactor property, define the possible values, and let the app pick the right one on startup?
To help answer this, lets look at two standard properties that already existing in GWT - locale and user.agent. Useragent detection is managed in the com.google.gwt.useragent.UserAgent module - properties are defined, a way to select a property is listed, and some helpful 'make sure that this wiring worked' bits are added to the app. Possible locales are started in com.google.gwt.i18n.I18N, but are designed to be extended within your own app. There is lots of extra stuff in here as well, defining how to pick which locale should be activated. We'll want to steal the idea of pre-defining the possible formfactors from user.agent, and will want the idea of reading the right formfactor from the locale code.
First, define the property.
<define-property name="formfactor" values="desktop, mobile" />
In this example, we'll only allow these two possible values - in reality, you might want desktop (i.e. large and mouse/keyboard), tablet (large and touch), phone (small and touch), or some other variation on this.
Next, decide how to read the right property value. There are two basic ways to do this - via a simple snippet of javascript, written in your module file, and by writing a class that generates JavaScript, based on some configuration settings. I'm going to go with the simplest one first, and let you work out how to actually detect this detail in javascript (update the question or comment if you can clarify further what you have/need/expect):
<!-- borrowing/adapting from
http://code.google.com/p/google-web-toolkit/wiki/ConditionalProperties -->
<property-provider name="formfactor"><![CDATA[
{
var ua = window.navigator.userAgent.toLowerCase();
if (ua.indexOf('android') != -1) { return 'mobile'; }
if (ua.indexOf('iphone') != -1) { return 'mobile'; }
return 'desktop';
}
]]></property-provider>
Again, this goes in the module, and defines some simple JavaScript to pick the value for formfactor - if the useragent contains the string 'android' or 'iphone', activate the mobile value, otherwise activate desktop. This code will be placed in your .nocache.js file, and used to pick the right permutation (with the right entrypoint, as defined above).
Apart from Colin's detailed answer you might have a look at GWT's standard example for mobilewebapp - http://code.google.com/p/google-web-toolkit/source/browse/#svn%2Ftrunk%2Fsamples%2Fmobilewebapp
The example FormFactor.gwt.xml - http://code.google.com/p/google-web-toolkit/source/browse/trunk/samples/mobilewebapp/src/main/java/com/google/gwt/sample/mobilewebapp/FormFactor.gwt.xml
You can use replace with
<replace-with class="webapp.client.MobileAppEntryPoint">
<when-type-is class="webapp.client.WebAppEntryPoint" />
<any>
<when-property-is name="formfactor" value="mobile"/>
</any>
</replace-with>
NOTE :i am not tried with entry point class ..but working fine for some Widget classes
For details refer Gwt differed binding
SOLVED:
Okay, thanks to everyone who replied. I used a little bit of everyones answer to get to the solution! Firstly I followed SSRs and had a look at the example FormFactor.gwt.xml file. I copied this into my project and referred to it in my App.gwt.xml file. I then followed Colins and added the following code to my App.gwt.xml file in order to load a different EntryPoint based upon form factor:
<entry-point class="webapp.client.AbstractEntryPoint" />
<replace-with class="webapp.client.WebAppEntryPoint">
<when-type-is class="webapp.client.AbstractEntryPoint" />
<when-property-is name="formfactor" value="desktop"/>
</replace-with>
<replace-with class="webapp.client.MobileAppEntryPoint">
<when-type-is class="webapp.client.AbstractEntryPoint" />
<when-property-is name="formfactor" value="mobile"/>
</replace-with>
Related
While migrating from GWT 2.7.0 to 2.8.2 I came upon property:
<define-configuration-property name="CssResource.gssDefaultInUiBinder"
is-multi-valued="true" />
If this is left as it is, I get an error: The configuration property named CssResource.gssDefaultInUiBinder is already defined with a different 'is-multi-valued' setting.
Does that mean that I can't set attribute is-multi-valued to already defined property? Why would this work with GWT 2.7.0 then? Can anyone give me an explanation about this attribute? Because I am failing to find one...
Attribute set in GWT resources:
<!-- The default for GSS in UiBinder -->
<define-configuration-property name="CssResource.gssDefaultInUiBinder" is-multi-valued="false" />
gwt/user/src/com/google/gwt/resources/Resources.gwt.xml
Correct - you should not be trying to change is-multi-valued, it doesn't really make any sense. You can't re-define a property or configuration-property after it has been set, you can only set the value.
If you want to turn the gss-in-ui-binder flag on, use this:
<set-configuration-property name="CssResource.gssDefaultInUiBinder" value="true" />
If you want to turn it off, either do nothing, or do this:
<set-configuration-property name="CssResource.gssDefaultInUiBinder" value="false" />
I have a problem with internationalization. I'm trying to implement support two languages in my GWT application. Unfortunately I never found a complete example how to do it with the help of UiBinder. That is what I did:
My module I18nexample.gwt.xml:
<?xml version="1.0" encoding="UTF-8"?>
<module rename-to='i18nexample'>
<inherits name="com.google.gwt.user.User" />
<inherits name='com.google.gwt.user.theme.clean.Clean' />
<inherits name="com.google.gwt.i18n.I18N" />
<inherits name="com.google.gwt.i18n.CldrLocales" />
<entry-point class='com.myexample.i18nexample.client.ExampleI18N' />
<servlet path="/start" class="com.myexample.i18nexample.server.StartServiceImpl" />
<extend-property name="locale" values="en, fr" />
<set-property-fallback name="locale" value="en" />
</module>
My interface Message.java:
package com.myexample.i18nexample.client;
import com.google.gwt.i18n.client.Constants;
public interface Message extends Constants {
String greeting();
}
The same package com.myexample.i18nexample.client has three properties file:
Message.properties:
greeting = hello
Message_en.properties:
greeting = hello
Message_fr.properties:
greeting = bonjour
My UiBinder file Greeting.ui.xml:
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder
xmlns:ui="urn:ui:com.google.gwt.uibinder"
xmlns:g="urn:import:com.google.gwt.user.client.ui"
ui:generateFormat="com.google.gwt.i18n.rebind.format.PropertiesFormat"
ui:generateKeys="com.google.gwt.i18n.rebind.keygen.MD5KeyGenerator"
ui:generateLocales="default" >
<ui:with type="com.myexample.i18nexample.client.Message" field="string" />
<g:HTMLPanel>
<ui:msg key="greeting" description="greeting">Default greeting</ui:msg>
</g:HTMLPanel>
</ui:UiBinder>
When the application starts, I always get the output in the browser:
Default greeting
Why? What am I doing wrong?
I tried to run the application from different URL:
http://127.0.0.1:8888/i18nexample.html?gwt.codesvr=127.0.0.1:9997
http://127.0.0.1:8888/i18nexample.html?locale=en&gwt.codesvr=127.0.0.1:9997
http://127.0.0.1:8888/i18nexample.html?locale=fr&gwt.codesvr=127.0.0.1:9997
The result does not change. Although I expected in last case a message bonjour.
If for example I use a g:Buttton instead of the message ui:msg:
<g:HTMLPanel>
<g:Button text="{string.greeting}" />
</g:HTMLPanel>
Then I get as a result of the button with text "hello"
And if I enter the URL:
http://127.0.0.1:8888/i18nexample.html?locale=fr&gwt.codesvr=127.0.0.1:9997
The text on the button changes to "bonjour". Here everything works as expected. But why internationalization is not working in my first case?
And whether there is a difference between the following:
<ui:msg description="greeting">Default greeting</ui:msg>
<ui:msg description="greeting">hello</ui:msg>
<ui:msg description="greeting"></ui:msg>
Should there be different results in these cases? How to write properly?
Please explain to me the principles of internationalization in GWT and why my example does not work.
Any suggestions would be greatly appreciated.
First, the files should be named Message_fr.properties (resp. Message_en.properties), not Message.properties_fr (resp. Message.properties_en).
Then ui:msg et al. in UiBinder will generate an interface (extending com.google.gwt.i18n.client.Messages)), not use one that you defined. For that, you have to use {string.greeting} (where string is the ui:field you gave to your ui:with). The UiBinder generator will do a GWT.create() on the type class of your ui:with, which is what you'd have done in Java code:
Message string = GWT.create(Message.class);
String localizedGreeting = string.greeting();
In the implicit Messages interface (generated by UiBinder), the various ui:generateXxx attributes on the ui:UiBinder will be transformed into annotations on the interface (properties of the #Generate annotation, or the value of the #GenerateKeys annotation).
Then, one method will be generated for each ui:msg, where the attributes generate equivalent annotations (#Key, #Description) and the content of the ui:msg element is the value of the #DefaultMessage annotation. When you have or widgets inside the content, they'll be turned into arguments to the method and placeholders in the #DefaultMessage text (the values will be filled by UiBinder).
I'd suggest you make something working without UiBinder first, and understand how it works; then try the ui:msg in UiBinder, using -gen in DevMode or the compiler so you can see exactly what code does UiBinder generate (yes, it really only generates code that you could have written yourself by hand).
Also, you should add a <set-property name="locale" value="en, fr" /> or you'll still have the default locale around, despite the set-property-fallback (it'd just never be used)).
I'm using OpenRasta to create a Survey application.
I have a SurveyResource that is accessible at /surveys/{id} and editable at /surveys/{id}/edit
I'd now like to add questions to the survey, as that is the point of a survey, but I'm not sure what the most restful way of doing this is and how to set it up in OR.
I'm thinking I should have a QuestionResource (that has details of the question type, question text, etc) and it should be posted to /surveys/{id}/questions and handled by a question handler, but I can't work out how to configure OR.
I've pushed my project onto github at https://github.com/oharab/OpenSurvey/tree/add_question_to_survey
Can anyone help me?
Ben
it depends on the way you want to model your resources. It's perfectly possible that you'd never explicitly provide access to a single question, and would modify the entire survey document, like so:
PUT /surveys/123
<survey>
<link rel="update" href="/surveys/123" method="PUT"
type="application/vnd.mycorp.survey+xml" />
<question id="age">
<label>How old are you?</label>
<select>
<option>0 - 5</option>
<option>6 - 10</option>
<option>10 - 13</option>
</select>
</question>
</survey>
If you go this route, you could even use HTML, or HTML 5 for your content so it's easy to consume by clients. Now you're just modifying the entire survey document at once.
Alternatively, you might want to separately address each question, giving them an individual URI, which I think is what you're talking about, like so:
GET /survey/123
<survey>
<link rel="add-question" href="/survey/123/questions"
type="application/vnd.mycorp.surveyquestion+xml" method="POST" />
<question>
<link rel="delete" href="/questions/123-age" method="DELETE" />
<link rel="update" href="/questions/123-age" type="application/vnd.mycorp.surveyquestion+xml" method="PUT" />
<label>How old are you?</label>
<select>
<option>0 - 5</option>
<option>6 - 10</option>
<option>10 - 13</option>
</select>
</question>
</survey>
Neither of these is more RESTful than the other, the difference is only in granularity of call. If you need the granularity of the latter, then configure yourself a separate handler per resource as in
using(OpenRastaConfiguration.Manual)
{
ResourceSpace.Has.ResourcesOfType<Survey>().AtUri("/survey/{id}").HandledBy<SurveyHandler>();
ResourceSpace.Has.ResourcesOfType<Question>().AtUri("/questions/{id}").HandleBy<QuestionHandler>();
}
I have a feature which is provisioning 1 document library and 2 custom lists. A folder is included for each list containing the schema.xml for that list. Each folder also contains the associated forms (AllItems, DispForm, EditForm, NewForm, etc.). Everything deploys/works correctly but it seems a little redundant having the same forms copied into each list's folder. There is nothing special about these lists - the are basically a default doc library/generic list with additional fields provided through new content types (derived from Item/Document).
As far as I can tell these forms are pretty generic. Are there pre-installed forms that I can reference from my list so I don't have to deploy all of these extra files? Is there any reason I would not want to do this?
Update - moving xml in comment to original question for readability:
<Forms>
<Form Type="DisplayForm" Url="Forms/DispForm.aspx" WebPartZoneID="Main"/>
<Form Type="EditForm" Url="Forms/EditForm.aspx" WebPartZoneID="Main"/>
<Form Type="NewForm" Url="Forms/Upload.aspx" WebPartZoneID="Main"/>
<Form Type="NewFormDialog" Path="EditDlg.htm">
....
There are virtual defaults that are used if you don't specify a concrete page.
All lists use these template defaults unless you use a tool like SharePoint designer to customize the page. Then the template is used to create the concrete page and you can customize the look for a particular list without affecting others.
For my custom definitions, I use
<List>
...
<MetaData>
...
<Forms>
<Form Type="DisplayForm" Url="DispForm.aspx" SetupPath="pages\form.aspx" WebPartZoneID="Main" />
<Form Type="EditForm" Url="EditForm.aspx" SetupPath="pages\form.aspx" WebPartZoneID="Main" />
<Form Type="NewForm" Url="NewForm.aspx" SetupPath="pages\form.aspx" WebPartZoneID="Main" />
</Forms>
</MetaData>
</List>
If you have no reason to customize the out of the box version of these forms, you can use the virtual form and not deploy copies.
I'm trying to pass a parameter into a component that requires a System.TimeSpan. I'm only able to get the 'long ticks' ctor to resolve.
Here's a snippet of the config file:
<component id="timeInForce" type="System.TimeSpan, mscorlib">
<parameters>
<hours>0</hours>
<minutes>15</minutes>
<seconds>0</seconds>
</parameters>
</component>
<component id="FooSettings" type="Foo.FooSettings, Foo">
<parameters>
<tif>${timeInForce}</tif>
</parameters>
</component>
This is the exception:
Castle.MicroKernel.Handlers.HandlerException : Cant create component 'timeInForce'
as it has dependencies to be satisfied.
timeInForce is waiting for the following dependencies:
Keys (components with specific keys)
- ticks which was not registered.
Passing a tick value for the component parameter works, as in:
<parameters><tif>0</tif></parameters>
but this defeats the purpose.
What's happening (from what I can see) is that the ticks property is being incorrectly identified as a compulsory parameter (because it belongs to the constructor with the least number of arguments) even though all value types have a default parameter-less constructor.
However the constructor candidate matching the most parameters will still be selected even if you supply additional parameters (i.e. ticks) so you can work around this by just including ticks in the list of parameters:
<component id="timeInForce"" type="System.TimeSpan, mscorlib">
<parameters>
<ticks>0</ticks>
<hours>0</hours>
<minutes>15</minutes>
<seconds>0</seconds>
</parameters>
</component>
Here is a quick test to verify it works (which passes for against the castle trunk):
string xml = #"<?xml version=""1.0"" encoding=""utf-8"" ?>
<castle>
<components>
<component id=""timeInForce"" type=""System.TimeSpan, mscorlib"">
<parameters>
<ticks>0</ticks>
<hours>0</hours>
<minutes>15</minutes>
<seconds>0</seconds>
</parameters>
</component>
</components>
</castle>";
WindsorContainer container = new WindsorContainer(
new XmlInterpreter(new StaticContentResource(xml)));
TimeSpan span = container.Resolve<TimeSpan>("timeInForce");
Assert.AreEqual(new TimeSpan(0, 15, 0), span);
However, what I would suggest rather then the approach your using is to implement your own type converter, as discussed in the castle documentation.
That way you could develop your own shorthand form for a timespan i.e. "15m" or "2h15m" or whatever takes your fancy - making your config a little easier to read and maintain and working round the issues you're currently experiencing.