I'm trying to find a way to automatically convert links in a panel to hyper-links. So for example a user input is:
"And here you can find my awesome example: http://example.com"
Is it possible in wicket to add an anchor element to each "http://..." text, so the above example would output
"And here you can find my awesome example: http://example.com"
instead?
You can use Wicket's built in SmartLinkLabel.
From the Javadoc:
If you have email addresses or web URLs in the data that you are displaying, then you can automatically display those pieces of data as hyperlinks, you will not have to take any action to convert that data.
One way to do this is to extend Label and override onComponentTagBody
Something like:
public class AnchorizeLabel extends Label {
public AnchorizeLabel(String id, String body) {
super(id, body);
}
#Override
protected void onComponentTagBody(MarkupStream stream, ComponentTag tag) {
String newBody = createAnchors(getDefaultModelObjectAsString());
replaceComponentTagBody(stream, tag, newBody);
}
private String createAnchors(String body) {
// regex magic to create links
}
}
You can also accomplish this with a custom IModel or IConverter but I prefer the Label approach.
Related
I using a loop and each time this function is call but it add only one javascript file. But i want to trigger the functionality of that javascript file each time . Can anyone please help me?
#Override
public void renderHead(Component component, IHeaderResponse response) {
RawJsView rawJsView = RawJsViewPanel.this.model().getObject();
Map<String, String> requireJsLibraries = rawJsView.getRequireJsLibraries();
if (!requireJsLibraries.isEmpty()) {
System.out.println("requireJsLibraries if =========================>");
response.render(OnDomReadyHeaderItem.forScript(buildRequireJsConfig(requireJsLibraries)));
}
}
Wicket contributes just one occurrence of some JS code. See https://github.com/apache/wicket/blob/0c4b88e16a3ec7478fbc8f86991c6b07805ed821/wicket-core/src/main/java/org/apache/wicket/markup/head/OnDomReadyHeaderItem.java#L101
To overcome it you can do either:
Add something unique to your JS code for each contribution. E.g. pass an unused function parameter with a unique name.
Override #getRenderTokens() for each header item:
OnDomReadyHeaderItem item = new OnDomReadyHeaderItem(js) {
#Override
public Iterable<?> getRenderTokens()
{
return Collections.singletonList("javascript-domready-" + somethingUnique);
}
somethingUnique could be anything that is unique, e.g. a timestamp or UUID
I am using a Nebula GridTreeViewer for which I need to add filters like eclipse filters.
When we go to Window->Preferences, we get a filter on top of the left side tree which says 'type filter text'.
I tried the TreeViewer with the FilteredTree -
final FilteredTree filteredTree = new FilteredTree(parent, SWT.BORDER
| SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION,
new MyPatternFilter(), true);
TreeViewer treeViewer = filteredTree.getViewer();
The above code works fine for a TreeViewer.
Is there a similar way to attach such kind of a filter to a Nebula GridTreeViewer?
If yes, please tell me. Would be very helpful. Thanks.
You will have to create your own quick search adapter. Observe the code in FilteredTree.
I can't post my own adapter, since it's company property. Here are some hints.
Things you will need in your MyQuickSearchAdapter:
public QuickSearchAdapter(Composite parent) constructor
A setViewer(StructuredViewer) API that does this.viewer = viewer and this.viewer.addFilter(viewerFilter) (see below for viewerFilter)
An abstract method getLabelProvider() to access a viewer's LabelProvider (in our case, GridTreeViewer)
Creation methods for a Text field that will represent the quick search area.
(Optional) Creation method for a label/button that clears the text when clicked (as in FilteredTree) - although this is overkill, in my opinion.
private MyViewerFilter extends ViewerFilter nested class, that does the actual filtering. This will have a String instance field that holds the search text; this field will have a setter that will be called each time you type something in the filter box. Will look something like viewerFilter.setSearchText(filterBox.getText());. This nested class will also override the select(Viewer, Object, Object), which will use the getLabelProvider().getText(element) to extract the text for a certain cell. Something like:
// Automatically adds wildcard characters before and after search string:
public static final String QSEARCH_REGEX_PATTERN = "(.*)%s(.*)"; //$NON-NLS-1$
private class MyViewerFilter extends ViewerFilter
{
// --------------------- <Instance Fields> -----------------------
private String searchString;
// --------------------- <Setters> -----------------------
/**
* #param
* Text that goes inside the REGEX pattern
*/
public void setSearchText(final String searchString)
{
//this.searchString = "(.*)" + searchString.toLowerCase() + "(.*)"; //$NON-NLS-1$ //$NON-NLS-2$
this.searchString = String.format(QSEARCH_REGEX_PATTERN, searchString.toLowerCase());
}
// --------------------- <Overridden search method> -----------------------
#Override
public boolean select(final Viewer viewer, final Object parentElement, final Object element)
{
if (StringUtils.isEmpty(searchString))
return true;
final String text = getLabelProvider().getText(element);
if (StringUtils.isEmpty(text))
return true;
return text.toLowerCase().matches(searchString);
}
}
That's the hard part. After that, you just make a class called MyFilteredGridTreeViewer, and add the quick search adapter along side the grid viewer. Also remember to call quickSearchAdapter.setViewer(gridViewer), and you're done!
I would like my uiBinder to use a ClientBundle which will provide some runtime customized labels. Kind of a TextResource but not from a text file !
I tried with GwtCreateResource but from the DevGuide it seems like it's not possible. Am I right ? (create() and name() are the only methods available)
What I would like to achieve is something like this:
client bundle:
public interface MyWidgetResources extends ClientBundle {
GwtCreateResource<WidgetLabels> labels();
#Source("lol.css")
CssResource style();
}
labels class:
public final class MyWidgetLabels {
public String title() {
return load("mywidget-title");
}
public String banner() {
return load("mywidget-banner");
}
private String load(String key) {
// load from external..
}
}
uiBinder:
<ui:with type="com.package.MyWidgetResources" field="res"/>
<gwt:SimplePanel>
<gwt:Label text="{res.labels.title}"></gwt:Label>
<gwt:Label text="{res.labels.banner}"></gwt:Label>
</gwt:SimplePanel>
My code looks like this already but res.label.title does not work because GwtCreateResource can only serve as class instantiator (res.labels.create().title()).
Is there a solution for me ? Maybe with a custom ResourceGenerator ?
As long as MyWidgetLabels can be created by GWT.create, you can put anything you want into that type, and you can make it behave however you'd like. You will need the create reference in your uibinder as you suggested at the end of the post to actually build the object, so your lines will look about like this:
<gwt:Label text="{res.labels.create.title}"></gwt:Label>
Each . separated piece (except the first, which is a ui:field/#UiField) is a no-arg method to be called - you declared labels() in MyWidgetResources, create() already existed in GwtCreateResource, and you created title() in your own MyWidgetLabels type.
Since that first piece is a ui:field/#UiField, you could have another that references res.labels.create as something like labels so that later you could instead say:
<gwt:Label text="{labels.title}"></gwt:Label>
Finally, yes, you could build your own ResourceGenerator which would enable you to do whatever you wanted to emit the type in question, as long as you extended the ResourcePrototype type and had a getName() method.
I have a rather complex form in the way that the number of form fields is flexibel. In short, the model object is a TLabel (TranslationLabel) that contains a Map of values (translations). Language here is an enum so the idea is that the number of fields (text areas) for which a translation is given depends on the values in this enum.
This is my form (simplified):
public class TranslationEditForm extends Form {
private final static List<Language> LANGUAGES = newArrayList(Language.values());
public TranslationEditForm(String id, final TranslationLabelView label) {
super(id, new CompoundPropertyModel<TranslationLabelView>(label));
ListView<Language> textAreas = new ListView<Language>("translationRepeater", LANGUAGES) {
#Override
protected void populateItem(final ListItem<Language> itemLang) {
//loop through the languages and create 1 textarea per language
itemLang.add(new Label("language", itemLang.getModelObject().toString()));
Model<String> textModel = new Model<String>() {
#Override
public String getObject() {
//return the value for current language
return label.getValue(itemLang.getModelObject());
}
#Override
public void setObject(String object) {
//set the value for current language
label.getTranslations().put(itemLang.getModelObject(), object);
}
};
itemLang.add(new TextArea<String>("value", textModel).setRequired(true));
}
};
//add the repeater containing a textarea per language to the form
this.add(textAreas);
}
}
Now, it works fine, 1 text area is created per language and its value is also set nicely; even more when changed the model gets updated as intended.
If you submit the form after emptying a text area (so originally there was a value) then of course there is a validation error (required). Normal (wicket) behaviour would be that the invalid field is still empty but for some reason the original value is reset and I don't understand why.
If I override onError like this:
#Override
protected void onError() {
this.updateFormComponentModels();
}
then it is fine, the value of the field is set to the submitted value (empty) instead of the original value.
Any idea what is causing this? What is wicket failing to do because the way I've set up the form (because with a simple form/model this is working fine as are the wicket examples)?
Posted as answer, so the question can be marked as solved:
ListView does recreate all its items at render time. This means that the validation will be broken. Have a look at API doc of the ListView
Calling setReuseItems() on the ListView solves this.
Regards,
Bert
I'm working with some third-party software that creates querystring parameters with hyphens in their names. I was taking a look at this SO question and it seems like their solution is very close to what I need but I'm too ignorant to the underlying MVC stuff to figure out how to adapt this to do what I need. Ideally, I'd like to simply replace hyphens with underscores and that would be a good enough solution. If there's a better one, then I'm interested in hearing it.
An example of a URL I want to handle is this:
http://localhost/app/Person/List?First-Name=Bob&My-Age=3
with this Controller:
public ActionResult List(string First_Name, int My_Age)
{
{...}
}
To repeat, I cannot change the querystring being generated so I need to support it with my controller somehow. But how?
For reference, below is the custom RouteHandler that is being used to handle underscores in controller names and action names from the SO question I referenced above that we might be able to modify to accomplish what I want:
public class HyphenatedRouteHandler : MvcRouteHandler
{
protected override IHttpHandler GetHttpHandler(RequestContext requestContext)
{
requestContext.RouteData.Values["controller"] = requestContext.RouteData.Values["controller"].ToString().Replace("-", "_");
requestContext.RouteData.Values["action"] = requestContext.RouteData.Values["action"].ToString().Replace("-", "_");
return base.GetHttpHandler(requestContext);
}
}
Have you tried [Bind(Prefix="First-name")]? It might work...
One way would be with a custom model binder. Another way would be with an action filter. Use the model binder if you want to do this on a specific type. Use the action filter if you want to do this on a specific action or controller. So for the latter method you could do something like:
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var keys = filterContext.HttpContext.Request.QueryString.AllKeys.Where(k => k.Contains('-'));
foreach(var k in keys)
{
filterContext.ActionParameters.Add(
new KeyValuePair<string, object>(
k.Replace('-', '_'), filterContext.HttpContext.Request.QueryString[k]));
}
base.OnActionExecuting(filterContext);
}
I had the same problem. In the end rather than doing something too complex I just get the query string parameters using
string First_Name = Request["First-Name"];
You may want to check for NUlls incase the parameter is not there, but this sorted it out for me. You can also include an optional parameter for the ActionResult for test purposes etc..