I have a GWT application that features two frames (com.google.gwt.user.client.ui.Frame). Via Frame.setUrl(...) I can load arbitrary web pages without any problems. Of course, user then can click on links on the loaded pages, which in turn load the corresponding pages? How can I keep track of the currently loaded pages in both frames?
Below are my current attempt using two types of listeners; I found the code snippets on the Web. Both events fire, but still I don't know how to get the current loaded URL
import com.google.gwt.event.dom.client.LoadEvent;
import com.google.gwt.event.dom.client.LoadHandler;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.EventListener;
import com.google.gwt.user.client.ui.Frame;
public class BrowserTabFrame extends Frame implements EventListener {
public BrowserTabFrame() {
super();
sinkEvents(Event.ONLOAD);
addLoadHandler(new LoadHandler() {
#Override
public void onLoad(LoadEvent event) {
System.out.println(event.getSource());
// <iframe style="visibility: visible;" id="ext-gen17" src="http://..." class="gwt-Frame"></iframe>
// however, the src attribute never changes
}
});
}
#Override
public void onBrowserEvent(Event event) {
super.onBrowserEvent(event);
if (DOM.eventGetType(event) == Event.ONLOAD)
System.out.println(event.getCurrentEventTarget());
// [object HTMLIFrameElement]
// no idea what to do with it
}
}
Thanks for any hints!
Christian
The src attribute of an iframe will never change but the URL property of the contained document will. You can get this value using JSNI:
private native String getIframeUrl(IFrameElement frame) /*-{
if (frame.contentDocument !== undefined) {
return frame.contentDocument.URL;
} else if (frame.contentWindow !== undefined &&
frame.contentWindow.document !== undefined)
{
return frame.contentWindow.document;
} else {
return null;
}
}-*/;
...
Window.alert(getIframeUrl(myFrame.getElement()));
However note that, if the security context (any of protocol, domain or port number) of the iframe changes, the browser will not allow the containing application to access the document in the frame.
This is an extension of Jason's solution above. When I tried Jason's code it appeared that the returned URIs are missing hashes (aka fragments, URI suffixes beginning with '#'), and I needed these. After some digging around the DOM spec, the following worked:
public static native String getIframeUri(IFrameElement iframe) /*-{
if (iframe.contentDocument !== undefined) {
if (iframe.contentDocument.defaultView !== undefined
&& iframe.contentDocument.defaultView.location !== undefined) {
return iframe.contentDocument.defaultView.location.href;
} else {
return iframe.contentDocument.URL;
}
} else if (iframe.contentWindow !== undefined
&& iframe.contentWindow.document !== undefined) {
return iframe.contentWindow.document;
} else {
return null;
}
}-*/;
Where the only addition to Jason's code is the nested condition:
if (iframe.contentDocument.defaultView !== undefined
&& iframe.contentDocument.defaultView.location !== undefined) {
return iframe.contentDocument.defaultView.location.href;
Related
When I click on an AjaxLink, I would like to have a validation via JavaScript on the client side first (because the LocalStorage is queried) and then depending on the result, further JavaScript calls are made. How can i achieve this?
In a pseudo code it would look like this:
new AjaxLink<>("myId", myModel) {
#Override
public void onClick(AjaxRequestTarget target) {
boolean isCounterValid = target.appendJavaScript(checkCounter()); // i know that this is not possible, therefore pseudo code
if(isCounterValid) {
target.appendJavaScript(someOtherJavaScript());
}
else {
target.appendJavaScript(anotherJavaScript());
}
}
private String checkCounter() {
return "var count = window.localStorage.getItem('myCounter'); return count !== 1;";
}
private String someOtherJavaScript() {
return "change something";
}
private String anotherJavaScript() {
return "change other thing";
}
};
You need to send extra request parameters with the Ajax call when the link is clicked. For that you should override updateAjaxAttributes(AjaxRequestAttributes attributes) method of AjaxLink:
#Override
protected void updateAjaxAttributes(AjaxRequestAttributes attributes)
{
attributes.getDynamicExtraParameters().add("var count = window.localStorage.getItem('myCounter'); return [{\"name\":\"count\", \"value\": count}]");
}
This way inside AjaxLink#onClick() you can read the count via:
int count = getRequest().getRequestParameters().getParameterValue("count").toInt();
AJAX components and behaviors can customize AJAX attributes overriding updateAjaxAttributes and using a custom implementation of AjaxCallListener which exposes different method to hook into the AJAX request cycle. In you case you could use AjaxCallListener#getBeforeSendHandler.
For a full introduction to this topic (with examples) see user guide:
https://ci.apache.org/projects/wicket/guide/8.x/single.html#_ajax_request_attributes_and_call_listeners
I am trying to show 10,000 contacts on listview in xamarin forms using realm. But whenever user traverse to contact listing screen
it gets freezed and loads after a while.
Moreover , i have provided an option to search from list as well and that too gets stuck as search if performing on UI thread.
Following is the code to load data from realm
public override async Task Initialize(Object data )
{
private Realm _realmInstance = getRealm();
if (contactList != null)
{
contactList.Clear();
}
contactList = _realmInstance.All<Contact>().OrderByDescending(d => d.contactId).ToList();
// here the binding happens with realm data
contacts = new ObservableCollectionFast<Contact>(contactList);
}
public ObservableCollectionFast<Contact> contacts
{
get { return items; }
set
{
items = value;
OnPropertyChanged("contacts");
}
}
as it was taking time in loading i thought to fetch realm data in background and bind it on UI thread as follows
but that is throwing error
realm accessed from incorrect thread
await Task.Run(() => {
contactList = _realmInstance.All<Contact>().OrderByDescending(d => d.contactId).ToList();
});
if (contactList.Count() > 0)
{
ContactListView = true;
AddContactMsg = false;
}
else
{
AddContactMsg = true;
}
Device.BeginInvokeOnMainThread(() =>
{
contacts = new ObservableCollectionFast<Contact>(contactList);
});
i wanted to try limiting the results by using TAKE function of LINQ but unfortunately its not supported by realm yet. not sure how i can smoothly load records from realm to listview.
EDIT
as per the SushiHangover i have changed things from IList to IQueryable
public IQueryable<Contact> contacts
{
get { return items; }
set
{
items = value;
OnPropertyChanged("contacts");
}
}
public override async Task Initialize(Object data )
{
_realmInstance = getRealm();
contacts = dbContactList= _realmInstance.All<Contact>();
}
so far search is working pretty smoothly but IQueryable change leads to another issue. on repeatedly performing following steps results in app crash
tap on list item
detail page gets open then press back
scroll down to few records
perform step 1 and repeat
this results into stackoverflow error
04-19 06:05:13.980 F/art ( 3943): art/runtime/runtime.cc:289]
Pending exception java.lang.StackOverflowError thrown by 'void
md5b60ffeb829f638581ab2bb9b1a7f4f3f.CellAdapter.n_onItemClick(android.widget.AdapterView,
android.view.View, int, long):-2' 04-19 06:05:13.980 F/art (
3943): art/runtime/runtime.cc:289] java.lang.StackOverflowError: stack
size 8MB
Link to entire log file
code to fire item click command is
public ICommand OnContactSelectCommand => new Command<Contact>(OnContactSelect);
following code will open ups a detail page
private async void OnContactSelect(Contact contact)
{
if (contact != null)
{
await NavigationService.NavigateToAsync<ContactDetailViewModel>(contact.mContactId);
}
}
Note:
when i replace IQueryable with List i do not face any error
somehow my issue is related to realm github thread where user is getting exception on listView.SelectedItem = null while using IQueryable
here is my code of list view item tap
private static void ListViewOnItemTapped(object sender, ItemTappedEventArgs e)
{
var listView = sender as ListView;
if (listView != null && listView.IsEnabled && !listView.IsRefreshing)
{
// have commented this line because it was crashing the app
//listView.SelectedItem = null;
var command = GetItemTappedCommand(listView);
if (command != null && command.CanExecute(e.Item))
{
command.Execute(e.Item);
}
}
}
I want to create and AMP version of my website in ASP.NET MVC using .NET Core 2.0. Previously I had done some work with DisplayModeProvider instances in tha past on .Net framework, but that does not seem to be an option in .NET Core.
What I want to be able to do is alter the view names to be index.amp.cshtml rather than index.cshtml when my URL starts iwth /amp. What's the best way to achieve this in .NET Core?
You can do something like this using IViewLocationExpander. As it happens, I was playing with this a few days ago so I have some code samples to hand. If you create something like this:
public class AmpViewLocationExpander : IViewLocationExpander
{
public void PopulateValues(ViewLocationExpanderContext context)
{
var contains = context.ActionContext.HttpContext.Request.Query.ContainsKey("amp");
context.Values.Add("AmpKey", contains.ToString());
var containsStem = context.ActionContext.HttpContext.Request.Path.StartsWithSegments("/amp");
context.Values.Add("AmpStem", containsStem.ToString());
}
public IEnumerable<string> ExpandViewLocations(ViewLocationExpanderContext context, IEnumerable<string> viewLocations)
{
if (!(context.ActionContext.ActionDescriptor is ControllerActionDescriptor descriptor)) { return viewLocations; }
if (context.ActionContext.HttpContext.Request.Query.ContainsKey("amp")
|| context.ActionContext.HttpContext.Request.Path.StartsWithSegments("/amp")
)
{
return viewLocations.Select(x => x.Replace("{0}", "{0}.amp"));
}
return viewLocations;
}
}
iViewLocationExpander can be found in Microsoft.AspNetCore.Mvc.Razor
Then in your Configure Services method in Startup.cs, add the following:
services.Configure<RazorViewEngineOptions>(options =>
{
options.ViewLocationExpanders.Add(new AmpViewLocationExtender());
});
What this will do is update the view locations per request to insert .amp before .cshtml any time the URL either starts with /amp or there is a query string key of amp. If your AMP views don't exist, it might blow-up a little, I've not fully tested it, but it should get you started.
You can define this Middleware :
public class AmpMiddleware
{
private RequestDelegate _next;
public AmpMiddleware(RequestDelegate next)
{
_next = next;
}
public Task Invoke(HttpContext context)
{
const string ampTag = "/amp";
var path = context.Request.Path;
if (path.HasValue)
{
var ampPos = path.Value.IndexOf(ampTag);
if (ampPos >= 0)
{
context.Request.Path = new PathString(path.Value.Remove(ampPos, ampTag.Length));
context.Items.Add("amp", "true");
}
}
return _next(context);
}
}
public static class BuilderExtensions
{
public static IApplicationBuilder UseAmpMiddleware(this IApplicationBuilder app)
{
return app.UseMiddleware<AmpMiddleware>();
}
}
And call it in Startup:
app.UseAmpMiddleware();
Then can check in page and simple set another layout or limit some code, in his way no need to create separate page for amp version:
#if (HttpContext.Items.ContainsKey("amp"))
{
<b>Request AMP Version</b>
}
I've currently faced a rather simple issue which eventually put me to a dead end. I am building an application that uses Xamarin Forms and want to change a masking character when user enters password from a bullet to an asterisk.
For entering password I'm using Entry control in Portable lib project in my content page (in VS2017 professional):
<Entry x:Name="Entry_Password" Placeholder="Password" IsPassword="True" />
I know that I probably should create a custom Renderer in Android project for this one, but would really appreciate how to do it for this specific purpose.
Am sure the converter answer will work , but as a personal preference i dont like it. this looks like a renderer job to me .
and here is how i would do it(example only in android because i dont have ios, but its fairly simple to implement it there)
Usage Xamarin forms
<controls:PasswordBox Placeholder="Password"/>
The Renderer (Android)
[assembly: ExportRenderer(typeof(PasswordBox), typeof(PasswordBoxRenderer))]
namespace PasswordAsterisk.Droid.Renderers
{
public class PasswordBoxRenderer : EntryRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
{
base.OnElementChanged(e);
if (Control != null)
{
Control.InputType = Android.Text.InputTypes.TextVariationPassword |
Android.Text.InputTypes.ClassText;
Control.TransformationMethod = new HiddenPasswordTransformationMethod();
}
}
}
internal class HiddenPasswordTransformationMethod : Android.Text.Method.PasswordTransformationMethod
{
public override Java.Lang.ICharSequence GetTransformationFormatted(Java.Lang.ICharSequence source, Android.Views.View view)
{
return new PasswordCharSequence(source);
}
}
internal class PasswordCharSequence : Java.Lang.Object, Java.Lang.ICharSequence
{
private Java.Lang.ICharSequence _source;
public PasswordCharSequence(Java.Lang.ICharSequence source)
{
_source = source;
}
public char CharAt(int index)
{
return '*';
}
public int Length()
{
return _source.Length();
}
public Java.Lang.ICharSequence SubSequenceFormatted(int start, int end)
{
return _source.SubSequenceFormatted(start, end);
}
public IEnumerator<char> GetEnumerator()
{
return _source.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return _source.GetEnumerator();
}
}
}
full source code example in GitHub
An easyier way to do this would be to use a Converter to swap every letter in an asterisk and than when you request the value it is plain.
This is an interesting post that could help you with your problem: https://forums.xamarin.com/discussion/52354/is-there-a-way-to-partially-mask-an-entry-field-in-xamarin
It's imported to use oneway and not twoway!
Good luck
My problem: I am sending a request to a servlet from an AJAX function in a JSP.
The servlet processes the data and returns a ArrayList.
My question is how to handle the ArrayList inside AJAX, and display it as a table in same JSP.
The code is
function ajaxFunction ( ) {
// var url= codeid.options[codeid.selectedIndex].text;
url="mstParts?caseNo=9&cdid=QCYST0020E1";
// alert(cid);
var httpRequest;
if (window.XMLHttpRequest) {
httpRequest = new XMLHttpRequest();
} else if (window.ActiveXObject) {
httpRequest = new ActiveXObject("Microsoft.XMLHTTP");
}
if (httpRequest == null){ alert('null');}
alert(url);
httpRequest.open("GET", url, true );
httpRequest.onreadystatechange = function() { alertContents(httpRequest); };
//httpRequest.setRequestHeader('Content-Type', 'text/plain');
httpRequest.send(null);
alert('t1');
}
function alertContents(httpRequest) {
if (httpRequest.readyState == 4) {
var cType =httpRequest.getResponseHeader("Content-Type");
//document.write(httpRequest.toString());
// alert(cType);
// var xmlDoc=httpRequest.responseText;
//document.write(xmlDoc.toString());
// if (xmlDoc == null) {alert('null returned');}
if (!httpRequest.status == 200) {
alert('Request error. Http code: ' + httpRequest.status);
}
else
{
var profileXML = eval(<%=request.getAttribute("data")%>);
if ( profileXML != null){ alert('null'); }//else { alert(profileXML(0)); }
// httpRequest.getAttribute("data");
}
}
}
var profileXML = eval(<%=request.getAttribute("data")%>);
Firstly, I would recommend you to learn about the wall between JavaScript and JSP. JS runs entirely at the client side and JSP/Java runs entirely at the server side. They certainly doesn't run in sync as you seem to think. To learn more, read this blog article.
function ajaxFunction ( )
Secondly, I would recommend you to use an existing, robust, thoroughly-developed, well-maintained JavaScript library with Ajaxical capabilities such as jQuery instead of reinventing the AJAX wheel and fighting/struggling/worrying with browser specific issues/troubles/behaviors/pains. I would also recommend to use JSON as data transfer format between Java Servlet at server and JavaScript at client. In the Java side you can use the great Gson library for this.
Here's a kickoff example with all of the mentioned techniques. Let's start with a Servlet and a JavaBean:
public class JsonServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
List<Data> list = dataDAO.list();
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
response.getWriter().write(new Gson().toJson(list));
}
}
public class Data {
private Long id;
private String name;
private Integer value;
// Add/generate getters/setters.
}
The JsonServlet (you may name it whatever you want, this is just a basic example) should be mapped in web.xml on a known url-pattern, let's use /json in this example. The class Data just represents one row of your HTML table (and the database table).
Now, here's how you can load a table with help of jQuery.getJSON:
$.getJSON("http://example.com/json", function(list) {
var table = $('#tableid');
$.each(list, function(index, data) {
$('<tr>').appendTo(table)
.append($('<td>').text(data.id))
.append($('<td>').text(data.name))
.append($('<td>').text(data.value));
});
});
The tableid of course denotes the idof the <table> element in question.
That should be it. After all it's fairly simple, believe me. Good luck.