I make a fullcalendar in my tapestry 5.4 web page.
When I make a new Event or I click an existing event, the fullcalendar's method is called (select or eventClick). In these methods tapestry js method is called (zoneManager.deferredZoneUpdate("formZone", listenerURIWithValue);), because I want to refresh my jQuery dialog div (#formZone) what is a tapestry zone. And it works well functionally, the data appears.
However, I always see the refreshing "procedure" because after the zone-update part, the jQuery dialog is opened, but the refresh is not ending (I know because ajax call is asynchronous) and it causes an "ugly" refresh after the jQuery dialog is opened.
My goal is to define a callback function for deferredZoneUpdate or make this code sequence:
...
zoneManager.deferredZoneUpdate("formZone", listenerURIWithValue);
$('#wsDialog').dialog('open');
...
Thanks for the answers in advance!
Update:
calendar-init.js:
define(["jquery" , "t5/core/zone"], function($, zoneManager) {
return function(modifyEventLink, newEventLink, pageTurnLink, allDayText) {
$(document).ready(function() {
var calendarDiv = $('#calendar');
calendarDiv.fullCalendar({
//....init
eventClick: function(calEvent, jsEvent, view) {
// create modifyeventlink with id param
var listenerURIWithValue = appendQueryStringParameter(modifyEventLink, 'eventID', calEvent.id);
// ajax zone update
zoneManager.deferredZoneUpdate("formZone", listenerURIWithValue);
// open the worksheet dialog
$('#wsDialog').dialog('option', 'title', calEvent.title);
},
//...init
});});}}) // the code syntacs is good dont bother these :D
backend:
void onModifyEventLink() {
if(request.isXHR()) {
logger.debug("ModifyEventLink on.");
String eventID = (String) request.getParameter("eventID");
if(eventID == null) {
logger.error("wsDialog was not able to load because eventID is NULL!");
} else {
try{
wSheet = sheetService.find(Integer.valueOf(eventID));
if(wSheet != null) {
ajaxResponseRenderer
.addCallback(new JavaScriptCallback() {
#Override
public void run(JavaScriptSupport javascriptSupport) {
javascriptSupport.require("wsdialogs");
}};)
.addRender(formZone);
} else {
logger.warn("Worksheet with " + eventID + " not found.");
}
} catch (NumberFormatException e) {
logger.error("wsDialog was not able to load beacause eventID was not a number.");
logger.error("Exception: ", e.getLocalizedMessage());
}
}
} else {
logger.debug("ModifyEventLink on, request is not XHR (ajax)");
}
}
(module) wsdialogs.js:
define(["jquery" , "t5/core/zone"], function($, zoneManager) {
console.log("wsdialog-js run");
$("#wsDialog").dialog('open');
});
tml:
<t:container
xmlns:t="http://tapestry.apache.org/schema/tapestry_5_4.xsd"
xmlns:p="tapestry:parameter">
<t:jquery.dialog t:clientId="wsDialog" t:id="wsDialog" title="${message:wsheet-new}" style="display: none;">
<t:zone t:id="formZone" id="formZone">
<t:form t:id="worksheetForm" t:type="form" t:zone="^">
....
</t:form>
</t:zone>
</t:jquery.dialog>
</t:container>
public class ComponentWithZone {
#Inject
private AjaxResponseRenderer ajaxResponseRenderer;
...
public void onSomeEventFromClient() {
ajaxResponseRenderer.addRender("zone-id-to-update", zone.getBody()).addCallback(new JavaScriptCallback() {
#Override
public void run(JavaScriptSupport javascriptSupport) {
javascriptSupport.require("modal").invoke("showModal").with("#dialog-id");
}
});
}
}
This example is with bootstrap modal included as tapestry module.
When tapestry refresh zone div with content it will trigger showModal function.
UPD: Forgot to mention that this example assumes that you have modal module.
Here is example of mine:
(function(){
define(["jquery", "bootstrap/modal"], function($, modal) {
return {
showModal: function(id) {
$('#'+id).modal('show');
},
hideModal: function(id) {
$('#'+id).modal('hide');
}
};
});
}).call(this);
Instead of bootstrap/modal you can use any module, but don't forget to include it in META-INF/modules.
Related
I am loading the webpage in webview using WebChromeClient(). The webpage has a dropdown whenever the user select's item from that dropdown I need to show a toast. For this, I'm following official doc I've implemented the same as the doc says. still, I'm getting the error in the console. "showToast is not a function".
In Fragment:
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val webSettings = webView.settings
webSettings.javaScriptEnabled = true
webSettings.domStorageEnabled = true
webSettings.databaseEnabled = true
webView.addJavascriptInterface(WebAppInterface(requireContext()), "Android")
webView.webChromeClient = object : WebChromeClient() {
override fun onConsoleMessage(consoleMessage: ConsoleMessage): Boolean {
Log.i(TAG, consoleMessage.message())
return true
}
override fun onProgressChanged(view: WebView?, newProgress: Int) {
super.onProgressChanged(view, newProgress)
if (newProgress == 100) {
if (webView != null) {
webView.settings.builtInZoomControls = true
webView.settings.displayZoomControls = false
webView.loadUrl("javascript:loadMobileDashboard($data);")
}
}
}
}
webView.loadUrl(url)
}
WebAppInterface:
class WebAppInterface(private val context: Context) {
private val TAG = WebAppInterface::class.java.simpleName
#JavascriptInterface
fun showToast(toast: String) {
Log.d(TAG, "showToast: $toast")
}
}
I tried several changes and searched about it on the internet didn't work single solution. Please let me know what mistake am making here. Thanks :)
Create an html page in your assets folder, let's say named dropDown.html.
Copy this code into that file
<input type="dropDown" value="Hello" onClick="showToastInWebView('strMsg')" />
<script type="text/javascript">
function showToastInWebView(toast) {
Android.showToast(toast);
}
</script>
Now load url like this
myWebView.loadUrl("file:///android_asset/dropDown.html");
Note: webView does not invoke the JS function you have added a bridge to, You need to use your own webpage(in this case which is dropDown.html) that does indeed invoke the function, either local(our case) or on the web.
I have a cordova (android) app with window popout using window.open javascript that override with cordova inAppBrowser when device is ready refer to the code below:
document.addEventListener("deviceready", onDeviceReady, false);
function onDeviceReady() {
window.open = cordova.InAppBrowser.open;
}
Then i want to set an event when user press phone back button or press "x" button to close the popout a dialog will pop out and asked "Are you sure? Y/N" before closing window popout. The code look like this:
var newwindow;
newwindow = window.open('something', '_self ', 'location=no');
newwindow.addEventListener('exit', function(event){ Exit() });
function Exit(){
navigator.notification.confirm(
'Are you sure?',
function(i){
if(i==2)
{
//exit the window popout
}
},
'App Name',
'Cancel,Exit'
);
But it doesn't work as i wanted, the popout window closed then dialog is prompt to user...How can i show a dialog and decides whether to close popout window.
Note: Sorry for bad grammar, i try my best to explain my problem.
I have found a fairly easy solution (android) for simple prompt like "Are you sure" "yes/no?" by editing the inappbrowser.dialog.java file. This solution is only prompting for confirmation before closing inappbrowser, which is suitable for my case.
Modify the java file InAppBrowserDialog.java in this location:
[your cordova project]/platforms/android/src/org/apache/cordova/inappbrowser/
ADD REQUIRED IMPORTS:
import android.content.DialogInterface;
MODIFY THE onBackPressed() FUNCTION
FROM:
public void onBackPressed () {
if (this.inAppBrowser == null) {
this.dismiss();
} else {
// better to go through the in inAppBrowser
// because it does a clean up
if (this.inAppBrowser.hardwareBack() && this.inAppBrowser.canGoBack()) {
this.inAppBrowser.goBack();
} else {
this.inAppBrowser.closeDialog();
}
}
}
TO:
public void onBackPressed() {
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(context)
.setTitle("Exit")
.setMessage("You are about to exit, are you sure?")
.setPositiveButton("Exit", new DialogInterface.OnClickListener(){
public void onClick(DialogInterface dialog, int which){
if (inAppBrowser == null) {
dismiss();
}
else {
// better to go through the in inAppBrowser
// because it does a clean up
if (inAppBrowser.hardwareBack() && inAppBrowser.canGoBack()) {
inAppBrowser.goBack();
} else {
inAppBrowser.closeDialog();
}
}
}
})
.setNegativeButton("Cancel", new DialogInterface.OnClickListener(){
public void onClick(DialogInterface dialog,int which){
dialog.cancel();
}
});
alertDialogBuilder.create();
alertDialogBuilder.show();
}
I basically just create an alert dialog on top of checking for inappbrowser when back button is pressed.
We are implementing an app where we have communication between Javascript and c#. Our UIWebView has a button to invoke some native functionality. On a UIWebView i have an handler on ShouldStartLoad.
webView.ShouldStartLoad = myHandler;
bool myHandler (UIWebView webView, NSUrlRequest request, UIWebViewNavigationType navType)
{
}
This gets called everytime page loads. Indeed, i would like to only call it from an event from WebView such as on a button click.
From Javascript i have
window.location.href = "myapp://action?par1=abc&par2=def";
How to call a particular function from custom url?
Calling JavaScript from c#
I am trying to call back JavaScript from c# but it is not calling TestShow() function
wkWebView.EvaluateJavaScript(string.Format("TestShow()"), (r, e) =>
{
Console.WriteLine("In EvaluateJavaScript");
if (e != null) Console.WriteLine(e);
});
JavaScript side i have a Alert but it is not showing that alert
function TestShow()
{
alert("Hello! I am an alert box!!");
}
You can either continue using UIWebView and parse the NSUrlRequest to see if it is the call you're looking for. Then return true/false accordingly.
A better option would be to use WKWebView and create a custom message handler. Something like this:
1) Implement IWKScriptMessageHandler (tested on the default UIView created by Xamarin UIViewController)
public class UniversalView : UIView, IWKScriptMessageHandler
{
public void DidReceiveScriptMessage(WKUserContentController userContentController, WKScriptMessage message)
{
var msg = message.Body.ToString();
System.Diagnostics.Debug.WriteLine(msg);
}
}
2) Create user controller with a handler for "myapp" (this = the IWKScriptMessageHandler)
var userController = new WKUserContentController();
userController.AddScriptMessageHandler(this, "myapp");
3) Create a config with the controller
var config = new WKWebViewConfiguration
{
UserContentController = userController
};
4) Create the WKWebView with the config
var webView = new WKWebView(new CGRect(10, 100, 500, 500), config);
5) Call "myapp" from your JS code
<html><head><meta charset = "utf-8"/></head><body>
<button onclick="callCsharp()">Click</button>"
<script type="text/javascript">
function callCsharp(){
window.webkit.messageHandlers.myapp.postMessage("action?par1=abc&par2=def");
}</script></body></html>";
EDIT: In regards to evaluating JS from C# you need to be sure the HTML page has finished loading or otherwise the call will result in an error. You can handle navigation events by implementing IWKNavigationDelegate
public class UniversalView : UIView, IWKScriptMessageHandler, IWKNavigationDelegate
{
[Export("webView:didFinishNavigation:")]
public void DidFinishNavigation(WKWebView webView, WKNavigation navigation)
{
webView.EvaluateJavaScript("callCsharp()", (result, error) =>
{
if (error != null) Console.WriteLine(error);
});
}
Assign it to the WKWebView you created:
var webView = new WKWebView(new CGRect(10, 100, 500, 500), config)
{
WeakNavigationDelegate = this
};
I've for example this link /Site/Tris/tris.aspx?sessionId=8a657a7b15ee44c39063c8ae45a6ed3b
This is the js code:
<script type="text/javascript">
$(function () {
// Declare a proxy to reference the hub.
var proxy = $.connection.myHub;
proxy.client.test = function () {
$('input').hide();//for testing
};
// start connetion
$.connection.hub.start(function () {
var sessionId = $(document).getUrlParam("sessionId");
proxy.server.joinGroup(sessionId);
});
});
</script>
This is the hub:
public void JoinGroup(string groupName)
{
this.Groups.Add(Context.ConnectionId, groupName);
}
public void test(string x)
{
Clients.Group(x).test();
}
This is the aspx code when I do a step:
protected void Image_Click(object sender, ImageClickEventArgs e)
{
string s = "8a657a7b15ee44c39063c8ae45a6ed3b";
IHubContext context = GlobalHost.ConnectionManager.GetHubContext<MyHub>();
context.Clients.Group(s).test();
}
When I call context.Clients.Group(s).test(); in js goes returns into the $.connection.hub.start and rejoin in the group adn test() is not called!
Why? How could I do?
Thanks
The reason was that when I click on an image and there is an event in ASPX, it sends a POST request so the page is refreshed right after
proxy.client.test = function () {
$('input').hide();//for testing
};`
is called.
I've to do all of this using only js avoid the POST request and the refresh.
I want to a message when ajaxToolkit:AjaxFileUpload start uploading, is there a way to do this
By default AjaxFileUpload doesn't have such event. But as the AjaxControlToolkit is an open-source library, you can add it yourself. Download the recent library sources from this page: source codes, find out AjaxFileUpload control sources (/Server/AjaxControlToolkit/AjaxFileUpload folder) and add code below to the AjaxFileUpload.cs file:
[DefaultValue("")]
[Category("Behavior")]
[ExtenderControlEvent]
[ClientPropertyName("uploadStarted")]
public string OnClientUploadStarted
{
get
{
return (string)(ViewState["OnClientUploadStarted"] ?? string.Empty);
}
set
{
ViewState["OnClientUploadStarted"] = value;
}
}
after that, modify AjaxFileUpload.pre.js file:
// insert this code right after the _raiseUploadComplete method
add_uploadStarted: function (handler) {
this.get_events().addHandler("uploadStarted", handler);
},
remove_uploadStarted: function (handler) {
this.get_events().removeHandler("uploadStarted", handler);
},
_raiseUploadStarted: function () {
var eh = this.get_events().getHandler("uploadStarted");
if (eh) {
eh(this, Sys.EventArgs.Empty);
}
},
// modify the _doUpload method
_doUpload: function () {
if (!this._filesInQueue.length || this._filesInQueue.length < 1)
return;
this._raiseUploadStarted();
this._currentQueueIndex = -1;
if (!this._isFileApiSupports)
this._createIframe();
this._processNextFile();
}
Than build solution and enjoy with new functionality.
In current version (December 2013 Release Version 7.1213) of AjaxControlToolkit this event is availbale without any need for any source code modifications.
http://ajaxcontroltoolkit.codeplex.com/SourceControl/latest#Server/AjaxControlToolkit/AjaxFileUpload/AjaxFileUpload.cs