I am creating a web page with several tabs. To implement that I am using wicket AjaxTabbedPanel and several AbstractTab. In each tab I have tables with data and I am using a javascript script to make the tables sortable.
public TabbedPage() {
List<ITab> tabs = new ArrayList<ITab>();
tabs.add(new AbstractTab(new Model<String>("first tab")) {
public Panel getPanel(String panelId) {
return new TablePanel(panelId);
}
});
tabs.add(new AbstractTab(new Model<String>("second tab")) {
public Panel getPanel(String panelId) {
return new TablePanel(panelId);
}
});
add(new AjaxTabbedPanel("tabs", tabs));
}
When I load the page the table in the tab selected by default is sortable. However, as soon as I click any of the links to jump to other tabs (including the one of the tab already selected), none of the tables in any of the tabs allows me sort them (including the one that was previously working - the table in the default tab). If I refresh the page I can sort the table (of the tab selected in the moment of the refresh), but as soon as I click in any of links to switch tabs, the tables stop having the sortable capability again. Any ideas of why is this happening?
EDIT:
I just found that if I replace the AjaxTabbedPanel by TabbedPanel I don't have this problem. Although I'm still not sure why is that. Can anyone enlighten me?
add(new TabbedPanel("tabs", tabs));
Sorting the table by JavaScript is most likely a function called with a specific DOM-Id and seems to be executed 'onLoad'. it then accesses the currently displayed table and does it's work.
Changing the content of your Panel by Ajax doesn't trigger 'onLoad' so the function isn't executed again. TabbedPanel reloads the page and therefore executed your script.
Selecting a previous sortable table with AjaxTabbedPanel doesn't work because of the dynamically generated DOM-Ids.
Your solution is to add a AjaxCallDecorator to the links from AjaxTabbedPanel or to include the script or at least the function call to your tabbed panels.
At least this it what comes to mind without seeing any sources...
EDIT:
You might want to look at The Wicket Wiki. There's a description on how to call js after clicking an AjaxLink. That's exactly what should solve your problem.
Summary: Just add
link.add(new AttributeAppender("onclick", new Model("myTableSortingScript();"), ";"));
to the links generated by AjaxTabbedPanel.
In Wicket 6.0 you can run JavaScript on a component basis: Just override renderHead(IHeaderResponse response) for your component:
#Override
public void renderHead(IHeaderResponse response) {
super.renderHead(response);
response.render(new OnLoadHeaderItem("initalizeMe(\"" + getMarkupId() + "\");"));
}
initializeMe(mycomponentId) is executed every time the component is loaded by the AjaxTabbedPanel. This also works with the standard TabbedPanel.
No real idea since I'm not sure what the code is doing but I had a similar problem with my Panel Manager. Basically if you dynamically load HTML into a panel (a div or another element) using "innerhtml" script in the content will not be executed.
To get around this I scan the loaded content for "script" tags and append them using the DOM methods - this does run the script and makes it available. My "load" method is:
// Load Content
Panel.load = function(Content) {
// "null" the old (to clear it)
Panel.innerHTML = null;
// Load the content
Panel.innerHTML = Content;
// Load Scripts
var AllScripts = Panel.getElementsByTagName("script");
var AllScriptsCnt = AllScripts.length;
for (var Cnt = 0; Cnt < AllScriptsCnt; Cnt++){
var CurScript = document.createElement('script');
CurScript.type = "text/javascript";
CurScript.text = AllScripts[Cnt].text;
Panel.appendChild(CurScript);
};
};
Again, not sure if this is the issue, but it sounds pretty much on target from my experience.
Related
This is my code:
comboBoxInstance.setInputPrompt("Something...");
comboBoxInstance.setNullSelectionAllowed(false);
Cookie comboCookie = getCookieByName("combo");
comboBoxInstance.select((comboCookie != null) ? comboCookie.getValue() : null);
final TextField textFieldInstance = new TextField("Textfield");
textFieldInstance.setInputPrompt("Something...");
Cookie tfCookie = getCookieByName("tf");
textFieldInstance.setValue((tfCookie != null) ? tfCookie.getValue() : null);
The problem is that the textfield works pretty well with the "Cookie setup". Only the combobox is refusing to work like it should.
The output is like this:
I've tried to use .setValue() instead of .select() but this has pretty much the same effect. I've also made sure that both the Cookie itself and the correct value are provided.
It may help to have a look at the part where the cookie is generated:
Cookie comboCookie = new Cookie("combo", comboBoxInstance.getValue().toString());
cookieProcessing(costcentreCookie); //<- sets maxage and vaadin related stuff (like adding the cookie)
Edit:
A few points to the data flow.
I'm generating a ComboBox with a SimpleJDBCConnectionPool's SQLContainer as the data container (coming from a TableQuery). Here's the initialization (executed in the constructor) in the combobox class:
private void init() throws SQLException {
this.setContainerDataSource(generateContainer());
this.setItemCaptionPropertyId("something");
}
The private method generateContainer() returns the SQLContainer of course.
This happens if I click on a particular button which opens up a dialog. This dialog is the fragment shown in the picture above. The combobox - of course - is part of it.
What one is supposed to do now is setting his data (get an item of the ComboBox) and hit save. The save button executes the routine to store the cookies. It's the code already mentioned above (Cookie comboCookie = new Cookie(...).
Okay, now the user is going to open up the dialog again. It's not important whether he reloads the application or just reopens the dialog (or does something else). It's basically the same in the app.
The dialog opens up and initializes the combobox (and the textfield) once again. However, this time it's supposed to gather the data out of the stored cookies. This is were the issue happens. This works well for the textfields (there are two but I've omitted one for shortening reasons) but not for the combobox, even tough it should've the exact same data as before. Hold in mind that it's the exact same class with the exact same initialization as when we stored the cookies in the first place.
I've the vague presumption, that it has to do something how the code is stacked. Maybe it hasn't finished loading the datacontainer while trying to set the appropriated value which then can't be found.
Edit2:
I've finally managed to reveal something. The ComboBox is indeed empty when the ".select()" is executed. However, this means, that the ComboBox is left untouched (it's only kind of "linked" to the datacontainer) until someone drops down the items. As soon as this happens, the items are there and I can possibly select them.
Is it supposed to work like this? O.o Am I able to fully initialize the combobox before I do something else? Something like:
private void init() throws SQLException {
this.setContainerDataSource(generateContainer());
this.setItemCaptionPropertyId("something");
this.gatherTheItems();
}
Edit3 - Test with ".setImmediate(true)"
I've changed the init to:
private void init() throws SQLException {
this.setContainerDataSource(generateContainer());
this.setItemCaptionPropertyId("SOMETHING");
this.setImmediate(true);
}
This didn't change anything. The combobox is still empty:
Finally! At first I've found a workaround which was like this:
for (Iterator it_IDS = combobox.getItemIds().iterator(); it_IDS.hasNext();) {
Object id = (Object) it_IDS.next();
if(id.toString().equals(cookie.getValue().toString())){
combo2.select(id);
break;
}
}
However, I couldn't believe that this was working since it doesn't change anything at the core problem. So I've investigated, that the RowID is built via a BigDecimal and voilà:
if(cookie != null) {
combobox.select(new RowId(new BigDecimal(cookie.getValue())));
}
I'm so happy right now :) Thanks for your patience kukis.
In case you came here because you're experiencing the same issue using a BeanItemContainer as datasource, bear in mind that you must implement both equals()and hashCode() methods on the underlying class for ComboBox's select() or setValue() methods to work.
You have plenty examples on Vaadin Forum on how to implement these methods:
ComboBox select value problem
Select or ComboBox does not Show Selected Property
Combobox select/setValue
By using PDFBox, it is easy to create a link that goes a particular page or page view by using PDPageDestination. For example, the following code will make a link that goes to page 9:
PDAnnotationLink link = new PDAnnotationLink();
PDPageDestination destination = new PDPageFitWidthDestination();
PDActionGoTo action = new PDActionGoTo();
destination.setPage(document.getPage(9));
action.setDestination(destination);
link.setAction(action);
Problem:
Instead of going to a particular page, I would like to go to the previous view.
For example, suppose in a PDF file, each of P.1 and P.2 has a link that goes to P. 9. Now I would like to put on P. 9 a link that goes back to where the user started.
If the user started out at P.1 and clicked the link to P.9, he arrives at P.9. When he clicks the link on P. 9, he will go back to P.1, where he came from. But If he started out at P.2, then the link at P.9 will go back to P.2 instead.
Question: How do I achieve this with PDFBox?
FYI, with Adobe Acrobat, this can be achieved by adding an "execute a menu item" action to a link, and then choosing "Previous View" as the menu item, as shown in this screenshot:
Link to Acrobat screenshot
With the guidance of Tilman, I managed to solve my own problem.
I cannot find a PDAction subclass that gives me the capability to add a "named action", so I created my own subclass, "PDActionNamed":
class PDActionNamed extends PDAction {
public static final String SUB_TYPE = "Named";
public PDActionNamed() {
super();
setSubType( SUB_TYPE );
}
public void setN( String s ) {
action.setName( "N", s );
}
}
To use the subclass,
PDAnnotationLink link = new PDAnnotationLink();
PDActionNamed action = new PDActionNamed ();
action.setN("GoBack"); // this is one of Acrobat's default named action
link.setAction(action);
It seems to work even on non-Javascript-supported PDF readers (e.g. SumatraPDF).
What you're talking about is a viewer dependant action; I don't think there is a way to do this generically but there should be ways to do this in Adobe Acrobat / Adobe Reader.
One such way is to insert a link that triggers an Action. The action could be a Javascript action and the Javascript could be relatively simple as the Acrobat Javascript API contains an "app" method called "goBack".
So, insert a link as you're doing right now. Insert not a GoTo action but a Javascript action. And set the Javascript to: "app.goBack()".
This should work in Acrobat (they have a similar example with a button form field in the Acrobat Javascript API reference. The question is whether it will work in other viewers as well and thus whether it will fulfil your business case.
I have some page that should have dynamic count of check boxes, and inputs depends on data received from database
now I do like this:
make rpc call on component load (getting data for inputs)
onSuccess add inputs dynamically on the form
result: form displayed without content(because it makes call async), only after resizing, it displays content properly
(probably I can fire resize event or redraw with my self, don't know how.. )
question: I am new in GWT, What is the best way to do this task? (Now i am using gwt-ext http://gwt-ext.com/, but I think it's no matter )
update: to refresh panel it's possible to call doLayout();
I'm not familiar with gwt-ext but in "vanilla" gwt you have two options:
Refresh your widget (that should show the result) in the onSuccess method
Proceed with the rest of your code not until the result returned.
To get a bit more precise i would need more of your code.
I had a similar challenge, the content of my widget was loading for a few seconds. I display a ""Loading, please wait ..."" label until the widget is loaded:
final VerticalPanel mainPanel = new VerticalPanel();
initWidget(mainPanel);
mainPanel.add(new Label("Loading, please wait ..."));
mainPanel.add(new myCustomWidget()); // this constructor uses RPC to get content
Timer t = new Timer()
{
public void run()
{
if (!mainPanel.getWidget(1).isVisible()) {
// do nothing
} else {
// remove label "Loading, please wait ..."
mainPanel.remove(0);
// stop timer
cancel();
}
}
};
// repeat every 30 miliseconds until myCustomWidget is visible
t.scheduleRepeating(30);
GWT FileUpload comes as a widget that produces so that one can upload a file during form submit (at least it's how I understand it :) ) What I want to do is to make it a better-looking and get rid of standard "Browse..." button.
Since I don't have good GWT experience (and no JavaScript), I looked for existing solutions and found quite a good project - gwtupload. It's good, but I realized I'd love to have my own miniature version (and also, I was curious about how it works). So I browsed through code and tried to extract the magic part. I realized that GWT FileInput is used, but it's not shown, and Button clicks are delegated to this FileInput. The code I tried to extract (only the part that delegates the click) after reviewing sources of gwtupload contains this tricky elem.click() JSNI:
class MyUpload extends Composite {
private static native void clickOnInputFile(Element elem) /*-{
elem.click();
}-*/;
public MyUpload() {
final FileUpload upload = new FileUpload();
AbsolutePanel container = new AbsolutePanel();
// container.add(upload);
Button btn = new Button("My Browse..");
btn.addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
clickOnInputFile(upload.getElement());
}
});
container.add(btn);
initWidget(container);
}
}
But this seems not to work: clicking on 'My Browse..' results in no effect (just in case I also tried running with un-commented container.add(upload) line) . Could you please help me in understanding what's wrong/missing in this code sample?
Thank you in advance.
P.S. I know that I have to place it on the FormPanel, and I know the rest about how to perform the actual submit/handling in Servlet; the only thing I want to do is this kind of decoration.
Since I have not received any answers, I had to have more investigation of this issue, so I performed a deeper code analysis of gwtupload project in order to understand how GWT FileUpload (which gets transformed into ) can be decorated.
It turned out that element.click() will only work in browsers which support #click() method (IE, Chrome, Safari). Actually, Manuel Carrasco Moñino - project author - mentions it within comments. There's second approach (for Firefox & Opera) that uses hack when FileInput is placed on transparent panel, which however is placed over some decorated button (using absolute positioning); comment by Manuel:
When the user puts his mouse over the button and clicks on it, what really happens is that the user clicks on the transparent file input showing the choose file dialog.
After that, the main work is correctly applying style attributes to elements.
Thus, there are two implementations of custom file upload component, and GWT deferred binding is used to instantiate them depending on Browser.
As for example I mention in my question, there're few fixes ("upload" has to be added to to the container, and it can be set to #setVisible(false)):
class MyUpload extends Composite {
private static native void clickOnInputFile(Element elem) /*-{
elem.click();
}-*/;
public MyUpload() {
final FileUploadWithMouseEvents upload = new FileUploadWithMouseEvents();
AbsolutePanel container = new AbsolutePanel();
container.add(upload);
upload.setVisible(false);
Button btn = new Button("My Browse..");
btn.addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
clickOnInputFile(upload.getElement());
}
});
container.add(btn);
initWidget(container);
}
}
This example works fine in IE8.
P.S. Thanks to Manuel for his great library :)
I'm trying to load a URL into a JEditorPane or JTextPane but the URL is a dynamically generated PHP page. I then want to process the output from the PHP page in my Java application. The PHP page will always output at least one String that I can use to check that it's generated correctly.
If I try and process the page straight after setting the page using
JEditorPane.setPage(URL);
if( outputTracker.getText().contains("desktop_process") )
it returns a blank HTML page, even if I specify a text/plain content type for the JEditorPane:
System.out.println(outputTracker.getText() );
I assume this is because the PHP page hasn't finished loading as the method below will return the correct output every time.
At the moment I'm setting the page and then starting a Swing Timer and checking every 200ms if the page contains the correctly generated String:
private void getPageBtnActionPerformed(java.awt.event.ActionEvent evt) {
outputTracker.setPage("URL_GOES_HERE?variables=x&y=a");
check_response_timer.start();
}
ActionListener checkAction = new ActionListener() {
public void actionPerformed(ActionEvent evt) {
if( outputTracker.getText().contains("desktop_process") ) {
System.out.println("Checking results...");
check_response_timer.stop();
process_response();
} else {
num_checks++;
System.out.println("Checking results...");
if( num_checks == 10 ) {
check_response_timer.stop();
checkLater = true;
responseLbl.setText("Connection timeout. Please click reconnect to check again.");
num_checks = 0;
}
}
}
};
private Timer check_response_timer = new Timer(200,checkAction);
This works fine.
At current server loads and the current complexity of the PHP pages being loaded the loop stops after the first iteration but it just seems a little inefficient and I don't want to have to keep checking if the page is going to take several seconds to load during heavy server loads or on more complex PHP pages.
I'm wondering if there's a better way to check that the page has finished loading.
I was wondering if I could use the JEditorPane.read(inputStream) method or set the page in a Swing Background Worker thread and then process the output of the PHP page when the worker's done() is called.
And is there a better way of loading the PHP output, reading it straight into a string from the dynamically generated output without the use of an editor pane as the editorpane isn't visible anyway?
Hope this is clear enough.
Thanks.
You can add a PropertyChangeListener to the editor pane:
editorPane.addPropertyChangeListener("page", ...);
However, this will only tell you when the main page is loaded. It won't tell you when images or other related files have finised loading.