Avoid back button using vaadin - button

I develop RIA application using Vaadin CDI addon.
About the app : it has two views(viewA and viewB) which maintained by Navigator.
User story is pretty simple:
User enters viewA
Perform some business stuff
Redirects to viewB
Using address bar to go some external website(ex. google.com)
Press back and it goes to he lastest page what he saw(viewB), instead of viewA
Any suggestions/tips-n-tricks how to avoid redirecting to viewB, but redirect to viewA?
Vaadin Forum quiet about this thing.
Thank you

I had same problem but resolved using following code:
getUI().getNavigator().addViewChangeListener(new ViewChangeListener() {
public boolean beforeViewChange(ViewChangeEvent event) {
return changeView;
}
#Override
public void afterViewChange(ViewChangeEvent event) {
// TODO Auto-generated method stub
}});
Set changeView = true only through proper navigation's (eg: On button clicks).
This how you can avoid navigation's using browser back button. In this case if user uses any of browser buttons the view does not changes and it remains on same page.

You could override View.enter(...) in your ViewB, and, according to your application state, update your view URI using Page.getCurrent().setUriFragment(recentUrl, false);

Related

Detect a change of iframe in page detail view in magnolia

Is there a way to detect which node is being rendered when the user selects a link within the pages detail app and only the iframe changes? If just the the iframe is changing I need a mechanism that can call the parent page and send the path of the node that is being rendered in the iframe. We run Magnolia EE 5.6.11.
My issue is that I have a ValueChangeListener in a ComboBox that I use as a versionSelector in a PageBar extension in the pages detail app.
// Create a selection component;
private ComboBox versionSelector = new ComboBox();
private Listener listener;
private boolean isSettingValue;
public VersionSelectorViewImpl(){
construct();
}
private void construct() {
versionSelector.setVisible(false);
versionSelector.setSizeUndefined();
versionSelector.setImmediate(true);
versionSelector.setNullSelectionAllowed(false);
versionSelector.setTextInputAllowed(false);
//setup listener for the selected item
versionSelector.addValueChangeListener(new Property.ValueChangeListener() {
#Override
public void valueChange(Property.ValueChangeEvent event) {
if (listener != null) {
listener.versionSelected((Object) event.getProperty().getValue());
}
}
});
}
The implementation is similar to the LanguageSelector or VariantSelector. When someone activates a hyperlink in the page template the iframe changes and the valueChange method retrieves the wrong value (ie. the event is from the previous page).
When someone activates a link, the PagesEditorSubApp#updateNodePath calls the updateLocationDependentComponents which calls the PageBar.onLocationUpdate. This calls in our case the VersionSelector#setCurrentVersion method. At this point I would need to reload the page detail subapp so that the listener is correctly set to the new page. I tried using the pageEditorPresenter.refresh() method in the setCurrentVersion method but it didn't do it.
In Magnolia 5.x you need to fire ContentChangeEvent to trigger the refresh (and hope that subapp you want to refresh listens to it, which in case of page detail subapp shouldn't be a problem).
Or, since you mention LanguageSelector, you can indeed try to call PageEditorPresenter directly as it does from info.magnolia.pages.app.editor.pagebar.languageselector.LanguageSelector#languageSelected, tho unless you need to modify something in the presenter (eg. locale in the example above), it seems rather unnecessary coupling of the code.
Once you are migrating your code to Magnolia 6.x and new UI framework, you have more convenient way of triggering notification of datasource change which all the views consuming data from given source listen to and facilitating refresh that way (as is shown eg in PasteComponentAction here.

Xamarin Forms - Prism detect GoBack

Using Xamarin.Forms v4.5 and Prism v7.2
I have an APP with 3 pages (PageA, PageB and PageC).
From PageA, I can navigate to PageB and from PageB to PageC. From PageC, I can tap on the back button and go back to PageB.
My question is, when I navigate to PageB (either from PageA or PageC), is there a method that Prism provides to identify whether I end up to PageB by pressing the back button?
At this time Xamarin.Forms does not provide a way to hook into the underlying Navigation Service and intercept the full Navigation process in certain flows such as when someone clicks on a hardware back button. As a result we are limited in what we can do and are therefore not able to support IConfirmNavigation to allow you to prevent navigating away.
That having been said we are able to observe that a Page was popped and we are still able to invoke OnNavigatedFrom/OnNavigatedTo. You can easily determine what has occurred by getting the NavigationMode. To do this your code might look like this:
public void OnNavigatedTo(INavigationParameters parameters)
{
var mode = parameters.GetNavigationMode();
switch(mode)
{
case NavigationMode.New:
break;
case NavigationMode.Back:
break;
case NavigationMode.Forward:
break;
}
}

JXBrowser control over dialog website not responding

Hey im having issues with a website in the jxbrowser. it seems like it is running into a timeout or whatever and then in the jxbrowser there is a dialog showing up "website not responding" and i can click on "reload" or "leave".
Can I in any way access this dialog and overwrite it? For instance everytime i would get this dont ask but go to the homepage instead?
I'm having trouble finding this if it is even possible.
I found a solution. JXBrowser has a RenderAdapter where a function exists onRenderUnresponsive wich can be overridden. Look at this: https://jxbrowser.support.teamdev.com/support/solutions/articles/9000091687-detecting-unresponsive-web-page
In my case I simply want to reload the website:
Browser browser = new Browser();
browser.addRenderListener(new RenderAdapter() {
#Override
public void onRenderUnresponsive(RenderEvent event) {
browser.reloadIgnoringCache(false);
}
});

Display the content of parent page in SilverStripe

I have simple tree structure in SilverStripe.
ParentPage and ChildPage.
On ParentPage I display the list of ChildPages. But I don't want to make accessible url:
/parent-page/child-page
I want to allow only
/parent-page
That's why I did redirect in ChildPage index action to ParentPage:
class ChildPage_Controller extends Page_Controller
{
public function index()
{
$this->redirect('/parent-page/');
}
}
It works well on frontend. But in CMS after I click to ChidPage in tree, it redirects me editing the ParentPage. (not to frontend url but to admin/pages/edit/show/ParentPageID ). This happen only in Split or Preview mode.
Can you advice how to prevent it? Or is there some other option? Thanks!
In the init function you can check if the user has permission to view the CMS and if the page currently has the stage get variable set:
class ChildPage_Controller extends Page_Controller {
public function init() {
parent::init();
if (!($this->getRequest()->getVar('stage') && Permission::check('VIEW_CMS'))) {
return $this->redirect($this->Parent()->Link(), 301);
}
}
}
This way a normal user will be redirected and a CMS user that isn't viewing the page with ?stage=... set will be redirected. The preview / split panes always set the stage get variable so the page will never be redirected when viewed in the preview / split pane.
so finally I found the solution.
Preview pane is displayed in an iframe. And parent CMS frame binds for changing the url of preview pane. It's because when you click to some link in preview pane, CMS navigates you to edit that page. So also when I do the redirect from ChildPage to ParentPage, the CMS pane catches the change of url and editor is redirected to the ParentPage.
I haven't found the way, how to prevent it, finally I needed to edit javascript of CMS (LeftAndMain.Preview.js line 251).
iframe.bind('load', function() {
self._adjustIframeForPreview();
// Load edit view for new page, but only if the preview is activated at the moment.
// This avoids e.g. force-redirections of the edit view on RedirectorPage instances.
// self._loadCurrentPage();
$(this).removeClass('loading');
});
So I commented out this line "self._loadCurrentPage();"
In the comment was written "This avoids e.g. force-redirections of the edit view on RedirectorPage instances." But it did the redirect anyway.
Maybe there's better way how to do that, but I haven't found it.

Android navigation tabs: Restoring fragment view state

I'm trying to understand how to preserve fragment view state when fragments are used within navigation tabs. In my efforts, I've come across two problems that I cannot find any proper solutions to.
I have two tabs, Tab1 and Tab2. Tab1's layout is defined by FragmentA and Tab2's layout is defined by FragmentB.
I've followed the approach given here (edit: documentation has changed since this question was asked).
The first problem: Even though my views have IDs, their states are not fully restored when a fragment is re-attached (after a tab switch rotation). In particular: an EditText with an ID does indeed save its entered text, but it does not save its enabled status. Also, buttons do not save if they are enabled or disabled even though they have IDs. I've found two possible workarounds for this problem:
Use hide()/show() instead of attach()/detach() when switching tabs.
in onPause(), save the current fragment view state in a View instance variable of the fragment via getView(). In onCreateView(Bundle savedInstanceState) check if this field is non-null and if that is the case return the value of this field. This solution seems hacky, and I've been told that it might also introduce a memory leak in my app.
The second problem: Consider the following user interaction:
User starts on Tab1 and does some changes that put the view state of Tab1 in a different state than its default state (and we want the fragment to save this view state through tabswitches and device tilts).
User then goes to Tab2. User then tilts her/his device (still at Tab2).
User then swaps to Tab1 (at the new screen orientation).
Now, the problem is: when the user initially swaps from Tab1 to Tab2, the fragment is detached and thereby its view discarded (even though the fragment instance still lives). When the user then tilts the device, the activity - and thereby both FragmentA and FragmentB associated with it - are destroyed. Since FragmentA at this point does no longer have a view (remember: it was detached), we cannot save the state of its view elements (e.g., what buttons are enabled/disabled) during the call to FragmentA.onSaveInstanceState(Bundle savedInstanceState). How do you recover fragment view state in a situation like this? Is the only viable solution to save every single view element's different status flags as SharedPreferences? This seems way too complicated for such an "everyday job".
Problem 1:
Android does not save your view enabled state by default. It seems only things which are directly influenced by user actions (without additional code) are saved. For a normal View, no information is saved, and for a TextView, of which EditText is a subclass, the entered text is saved (if freezesText is set).
If you want to anything else to be saved, you will have to do it yourself. Here is an question with some answers that show how to implement custom view state saving. You can stick with attach/detach if you follow that approach.
Problem 2:
You are right in that Fragment.onSaveInstanceState(Bundle) can be called after your view has already been destroyed. However, this is not where you should be saving your view state. Android will call View.onSaveInstanceState() right before it destroys your views when detaching a fragment. It saves this state and gives it back to you when you attach the fragment again. This is exactly what happens when you flip between tabs normally with no rotations. Fragment.onSaveInstanceState(Bundle) is not called when detaching. Even if you rotate the device, the view state saved as a result of the detach will persist. If you implement View.onSaveInstanceState() as directed above, your view state will be saved and restored properly, even in the Tab1-Tab2-rotate-Tab1 scenario.
Side note:
The example code in the docs seems to have some problems when you try to rotate. The lifetime of the TabListener is the same as that of the Activity - a new one is created every time you rotate. This means it also loses its internal reference to the fragment, every time you rotate. Added fragments are recreated automatically and so there is no need for the TabListener to try to create a new instance and add it, after rotation. Instead, of the internal reference, it should just try to find the fragment with the appropriate tag in the fragment manager. After rotation it will still exist.
The other problem is with that the selected tab is not saved, but this is noted at the bottom of the example. You could save this in Activity.onSaveInstanceState(Bundle).
private ViewPager viewPager;
viewPager = (ViewPager) findViewById(R.id.pager);
mAdapter = new TabsPagerAdapter(getSupportFragmentManager());
viewPager.setAdapter(mAdapter);
viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageSelected(int position) {
// on changing the page
// make respected tab selected
actionBar.setSelectedNavigationItem(position);
}
#Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
}
#Override
public void onPageScrollStateChanged(int arg0) {
}
});
}
#Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
}
#Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
// on tab selected
// show respected fragment view
viewPager.setCurrentItem(tab.getPosition());
}
#Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
}

Resources