How to make SweetAlert work in JavaFx WebView - javafx

I am trying to get SweetAlert to work in JavaFx WebView.
I have a Web Application which uses SweetAlert in place of the default browser alert. Everything works fine when viewed through a conventional browsers.
Now I want to have have the same Web App run through JavaFx WebView.
The Problem is: The SweetAlert Confirm dialog box is not working in the JavaFx WebView.
This is the Ajax with the SweetAlert Code:
$(document).on('click', '#confirmOverage', function(e){
e.preventDefault();
$(this).attr("disabled",true);
var overageID = $(this).attr('overageValue');
if(overageID !== ""){
swal({
title: "Are You Sure ?",
text: "Do you really want to confirm this overage deposit ?",
icon: "info",
buttons: true,
dangerMode: true,
closeOnClickOutside: false,
})
.then((willDelete) => {
if (willDelete) {
$.ajax({
url: '<?=$fn;?>',
method: 'POST',
dataType: 'text',
data: {
oi: overageID
},
success: function(successResponse){
if(successResponse !== "" && successResponse.includes("SUCCESS:") === true){
successResponse = successResponse.replace("SUCCESS: ","");
swal({
title: "SUCCESS !",
text: successResponse,
icon: "success",
closeOnClickOutside: false,
});
}
else{
if(successResponse.includes("SORRY !") === true){
successResponse = successResponse.replace("SORRY !","");
}
else if(successResponse.includes("SORRY!") === true){
successResponse = successResponse.replace("SORRY!","");
}
else if(successResponse.includes("Sorry!") === true){
successResponse = successResponse.replace("Sorry!","");
}
else if(successResponse.includes("Sorry,") === true){
successResponse = successResponse.replace("Sorry,","");
}
swal({
title: "SORRY !",
text: successResponse,
icon: "error",
closeOnClickOutside: false,
});
}
}
});
}
else{
$(this).attr("disabled",false);
}
});
}
else{
swal({
title: "SORRY !",
text: "The Overage Parameter is required. Please Check and try again. Thank you",
icon: "error",
closeOnClickOutside: false,
});
$(this).attr("disabled",false);
}
})
This is the JavaFx WebView Code :
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.VBox;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javafx.stage.Stage;
public class main extends Application{
String url = "https://www.url.com/index.php";
public static void main(String[] args){
Application.launch(args);
}
#Override
public void start(Stage stage) throws Exception{
WebView myWebView = new WebView();
WebEngine engine = myWebView.getEngine();
engine.load(url);
engine.getConfirmHandler();
VBox root = new VBox();
root.getChildren().addAll(myWebView);
Scene scene = new Scene(root);
stage.setTitle("SCHOOL MANAGEMENT SYSTEM");
stage.setScene(scene);
stage.show();
}
}
Please, what is wrong and what is the correct way of doing this ?
Any help is appreciated. Thank you

I have finally solved the problem.
I think the issue wasn't with the JavaFx WebView.
I changed SweetAlert promise call:
.then((willDelete) => {
if (willDelete) {
......
......
}
});
To This
.then(function(proceed) {
if (proceed) {
.......
.......
}
});
That solved the problem.
This might help someone in the future

Related

Youtube iframe api: interact with MediaSession

I have an angular app with the Youtube IFrame API. When the website/pwa is used on an android device, and a Youtube video is playing, the app automatically creates a notification in the android notification tray, allowing you to see what video is currently playing.
I created my own playlist-controller, so I'm not using queueVideoById since I don't like the way the default youtube-iframe playlist-controller works (you cannot remove queued videos afterwards).
From my AppComponent I'm loading the YouTube IFrame API
app.component.ts
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit, OnDestroy {
constructor(private youtubeHelper: YoutubeHelper) {
this.youtubeHelper.loadApi().then((isLoaded) => {
this.player.playSong(song.playerInfo.id);
});
}
#ViewChild('player') player: YoutubePlayerComponent;
}
app.component.html
<body>
<youtube-player #player [domId]="'player'" ... (previousPressed)="onPreviousPressed()" (nextPressed)="onNextPressed()"></youtube-player>
</body>
This helper is used to load the IFrame API script. LoadApi inserts a script-tag with the src set to the youtube-iframe-url:
import { Injectable } from '#angular/core';
import { Promise } from 'q';
import { BehaviorSubject } from 'rxjs';
#Injectable({
providedIn: 'root'
})
export class YoutubeHelper {
static scriptTag: HTMLScriptElement = null;
public loadApi() {
return Promise<boolean>((resolve, reject) => {
if (typeof window !== 'undefined') {
if (YoutubeHelper.scriptTag === null) {
window['onYouTubeIframeAPIReady'] = () => {
this.apiReady.next(true);
resolve(true);
};
YoutubeHelper.scriptTag = window.document.createElement('script');
YoutubeHelper.scriptTag.src = 'https://www.youtube.com/iframe_api';
const firstScriptTag = window.document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(YoutubeHelper.scriptTag, firstScriptTag);
} else {
resolve(true);
}
} else {
resolve(false);
}
});
}
public unloadApi() {
return Promise((resolve) => {
if (typeof window !== 'undefined') {
if (YoutubeHelper.scriptTag !== null) {
YoutubeHelper.scriptTag.parentNode.removeChild(YoutubeHelper.scriptTag);
YoutubeHelper.scriptTag = null;
//console.log('Removed YouTube iframe api');
this.apiReady.next(false);
}
}
});
}
public apiReady = new BehaviorSubject<boolean>(
(typeof window === 'undefined')
? false
: window['YT'] !== undefined
);
}
When the iframe api script is inserted in the dom, the YoutubePlayerComponent deals with this by creating an instance of YT.Player (this happens at the this.youtubeHelper.apiReady subscription):
/// <reference path="../../../../node_modules/#types/youtube/index.d.ts" />
import { Component, OnInit, Input, Output, EventEmitter } from '#angular/core';
import { YoutubeHelper } from '../../helpers/youtube-api.helper';
import { SongProgress } from '../../entities/song-progress';
import { Song } from '../../entities/song';
import { BehaviorSubject } from 'rxjs';
#Component({
selector: 'youtube-player',
templateUrl: './youtube-player.component.html',
styleUrls: ['./youtube-player.component.scss']
})
export class YoutubePlayerComponent implements OnInit {
constructor(private youtubeHelper: YoutubeHelper) {
}
#Input() domId: string;
// Properties omitted for breverity
#Output() previousPressed: EventEmitter<any> = new EventEmitter();
#Output() nextPressed: EventEmitter<any> = new EventEmitter();
private player: YT.Player;
private isPlayerReady = new BehaviorSubject<boolean>(false);
ngOnInit() {
}
ngAfterViewInit() {
this.youtubeHelper.apiReady.subscribe((ready) => {
if (ready && !this.player) {
this.player = new YT.Player(this.domId, {
width: this.width,
height: this.height,
playerVars: {
autoplay: this._autoplay
},
events: {
onReady: (event) => {
this.isPlayerReady.next(true);
},
onStateChange: (state: { data: YT.PlayerState }) => {
}
}
});
// Attempt to give the player methods my very own implementation
this.player.previousVideo = () => {
this.previousPressed.emit();
};
this.player.nextVideo = () => {
this.nextPressed.emit();
};
console.log('player', this.player);
}
});
}
static mediaInit = false;
public playSong(youtubeId: string) {
if (this.isPlayerReady.value) {
this.player.loadVideoById(youtubeId);
} else {
console.log('Player not yet ready');
this.isPlayerReady.subscribe((value) => {
if (value === true) {
this.player.loadVideoById(youtubeId);
}
});
}
// Here is the code that's supposed to interact with the media session in the iframe.
if (!YoutubePlayerComponent.mediaInit) {
YoutubePlayerComponent.mediaInit = true;
let frame = <HTMLIFrameElement>document.getElementById(this.domId);
frame.contentWindow.navigator.mediaSession.setActionHandler('previoustrack', () => {
this.previousPressed.emit();
});
frame.contentWindow.navigator.mediaSession.setActionHandler('nexttrack', () => {
this.nextPressed.emit();
});
}
}
public play() { this.player.playVideo(); }
// Pause, stop methods omitted for breverity
}
After that the isPlayerReady is triggered, allowing a video to be played:
When calling YoutubePlayerComponent.playSong, it either waits for the YoutubePlayer to be ready (isPlayerReady) or immediately calls this.player.loadVideoById, which plays the requested video.
Having said this, the question is:
By default when a video is playing inside my website/pwa it displays a media notification as shown in the first image. I want to be able to navigate to the previous/next track in my own playlist. So I want to intercept these events:
According to this link it's possible to modify the mediaSession of the Window after playing a video, attaching custom handlers to the previous/next buttons in the android tray. But since the video (and off course the mediaSession) is being played from the iframe, it's not possible to modify the metadata:
navigator.mediaSession.metadata = new MediaMetadata({
title: 'Never Gonna Give You Up',
artist: 'Rick Astley',
album: 'Whenever You Need Somebody'
});
would become:
document.getElementById('player').contentWindow.navigator.mediaSession.metadata = new MediaMetadata({
title: 'Never Gonna Give You Up',
artist: 'Rick Astley',
album: 'Whenever You Need Somebody'
});
And just to check, while a video is playing the mediaSession of the mainWindow is empty:
navigator.mediaSession.metadata
> null
And the actual mediaSession should be available in:
document.getElementById("player").contentWindow.navigator.mediaSession
> Blocked a frame with origin "https://example.com" from accessing a cross-origin frame
So is there any way I can add previous/next buttons to the notification while using the Youtube iframe API, and handle these events?
If necessary, the entire project is available on GitHub

Full calendar - Can not refresh events in react

I use Full Calendar in my React project. I can not refresh the calendar although I make an update on the state.
Here is my sample code: https://codesandbox.io/embed/fullcalendar-react-jp7n1
In this sample, I change the title of events when user clicks on the Change title button, but nothing changes. I there anything that I miss?
Thanks for your help.
import React from "react";
import FullCalendar from "#fullcalendar/react";
import dayGridPlugin from "#fullcalendar/daygrid";
import timeGridPlugin from "#fullcalendar/timegrid";
import interactionPlugin from "#fullcalendar/interaction";
import "./styles.css";
import "#fullcalendar/core/main.css";
import "#fullcalendar/daygrid/main.css";
import "#fullcalendar/timegrid/main.css";
export default class DemoApp extends React.Component {
calendarComponentRef = React.createRef();
state = {
calendarWeekends: true,
calendarEvents: [
// initial event data
{ title: "Event 1", start: new Date() },
{ title: "Event 2", start: new Date() },
{ title: "Event 3", start: new Date() }
]
};
render() {
return (
<div className="demo-app">
<div className="demo-app-top">
<button onClick={this.changeTitle}>Change title</button>
</div>
<div className="demo-app-calendar">
<FullCalendar
defaultView="dayGridMonth"
header={{
left: "prev,next today",
center: "title",
right: "dayGridMonth,timeGridWeek,timeGridDay,listWeek"
}}
plugins={[dayGridPlugin, timeGridPlugin, interactionPlugin]}
ref={this.calendarComponentRef}
weekends={this.state.calendarWeekends}
events={this.state.calendarEvents}
/>
</div>
</div>
);
}
changeTitle = () => {
let events = [...this.state.calendarEvents];
events[0].title = new Date().toTimeString();
events[1].title = new Date().toTimeString();
this.setState({ calendarEvents: events });
};
}
Full calendar uses deep equality check to test for changes and since the object of the event inside the array is not changed (it's the same object by reference) it doesn't detect the change. You need to create a new event object to update it.
let events = [ ...this.state.calendarEvents];
events[0] = {
title: new Date().toTimeString(),
start: events[0] .start
}
events[1] = {
title: new Date().toTimeString(),
start: events[1].start
}
this.setState({ calendarEvents: events});

Setting Firebase data to property in html file

Okay so i am fairly new at ionic and i am experiencing this problem where by i am getting the users data from firebase but whenever i set it to the public variable and try and reference it in the html file, i am getting a log error of "cannot set 'variable name' to property of undefined". Here is my code for a more clearer explanation and understanding of what i am trying to achieve. Thank you.
.ts file:
import { Component } from '#angular/core';
import { IonicPage, NavController, NavParams,AlertController,
LoadingController, Loading } from 'ionic-angular';
import {AngularFireAuth} from 'angularfire2/auth';
import { MenuPage } from '../menu/menu';
import firebase from 'firebase';
import { first } from 'rxjs/operators';
#IonicPage()
#Component({
selector: 'page-account',
templateUrl: 'account.html',
})
export class AccountPage {
public userinfo;
constructor(public navCtrl: NavController, public navParams: NavParams,
private alertCtrl:AlertController, public fAuth:AngularFireAuth,
public loading:LoadingController) {
}
ionViewDidLoad() {
console.log('ionViewDidLoad AccountPage');
this.readData();
}
isLoggedIn(){
return this.fAuth.authState.pipe(first()).toPromise();
}
userStatus(){
const user = this.isLoggedIn()
if(user){
console.log('logged in');
this.readData();
}else{
}
}
async readData(){
let load = this.loading.create({
content: "Setting up your profile...",
spinner:'dots'
});
load.present();
await this.fAuth.authState.subscribe((user:firebase.User) =>{
if(user){
firebase.database().ref('/users/' +
user.uid).once('value').then(function(snapshot){
if(snapshot.exists()){
var data = (snapshot.val() && snapshot.val().username) ||
'Anonymous';
//this.userinfo = data;
console.log(data);
}else{
console.log("i need a name");
}});
}else{
console.log("not logged in, log in please");
this.alertLogin();
};
});
console.log(this.userinfo );
load.dismiss();
}
getName(){
let alert = this.alertCtrl.create({
title: 'Hello new friend! :) please can you tell us your name...',
inputs: [
{
name: 'name',
placeholder: 'name'
}
],
buttons: [
{
text: 'Cancel',
role: 'cancel',
handler: data => {
console.log('Cancel clicked');
this.navCtrl.setRoot(MenuPage);
}
},
{
text: 'Confirm',
handler: data => {
this.fAuth.authState.subscribe((user:firebase.User) =>{
firebase.database().ref('/users/' + user.uid).set({
username:data.name
});
});
}
}
]
});
alert.present();
}
alertLogin(){
//if user is not already logged in
let alert = this.alertCtrl.create({
title: 'Whoa there Sally! you need to log in first! :)',
inputs: [
{
name: 'email',
placeholder: 'email'
},
{
name: 'password',
placeholder: 'Password',
type: 'password'
}
],
buttons: [
{
text: 'Cancel',
role: 'cancel',
handler: data => {
console.log('Cancel clicked');
this.navCtrl.setRoot(MenuPage);
}
},
{
text: 'Login',
handler: data => {
this.login(data.email,data.password);
}
},{
text: 'Register',
handler: data => {
this.register(data.email,data.password);
}
}
]
});
alert.present();
}
async login(email,password){
try{
var login = await this.fAuth.auth.signInWithEmailAndPassword(
email,
password
);
if(login){
console.log("Successfully logged in!");
}
}catch(err){
console.error(err);
alert("Sorry we couldnt find you in our system :(");
this.navCtrl.setRoot(MenuPage);
}
}
async register(email,password){
try{
var reg = await this.fAuth.auth.createUserWithEmailAndPassword(
email,
password
);
if(reg){
this.getName();
console.log("successfully registered!");
this.navCtrl.setRoot(AccountPage);
}
}catch(err){
console.error(err);
}
}
logout(){
this.fAuth.auth.signOut();
}
}
.html file:
<ion-item>
<h1>{{userinfo}}</h1>
</ion-item>
Okay so i have tried basically everything and have decided to rather just upload the name to the database and write it locally in the storage of the application. I will just pull the name, along with further details later on in the application process. However if anyone finds an answer for this post, i would greatly appreciate it!

Ionic 3 FCM open specific pages when notification tapped when app is in background/closed

I can get the push notification when my apps is on background/closed and I can get the data in the payload of the notifications when i tapped it and open
"notification": {
"title": "Chat Messages",
"body": `You have received chat messages from ${userName}`,
"sound": "default",
"click_action":"FCM_PLUGIN_ACTIVITY",
"icon":"fcm_push_icon"
},
"data": {
"user_id" : from_user_id,
"user_name" : userName,
"type" : notification_type
}
but there is a problem which I can't make it open a specific page after i tapped the notification when in background/closed.
Here is my code in the app.components.ts:
import { Component, ViewChild } from '#angular/core';
import { Platform, NavController } from 'ionic-angular';
import { StatusBar } from '#ionic-native/status-bar';
import { SplashScreen } from '#ionic-native/splash-screen';
import { FCM } from '#ionic-native/fcm';
import { LoginPage } from '../pages/login/login';
import { TestpagePage } from '../pages/testpage/testpage';
#Component({
templateUrl: 'app.html'
})
export class MyApp {
#ViewChild('myNav') navCtrl: NavController
rootPage:any = LoginPage;
constructor(fcm: FCM, platform: Platform, statusBar: StatusBar, splashScreen: SplashScreen) {
platform.ready().then(() => {
// Okay, so the platform is ready and our plugins are available.
// Here you can do any higher level native things you might need.
statusBar.styleDefault();
splashScreen.hide();
fcm.onNotification().subscribe(function(data) {
if(data.wasTapped) {
alert('HI');
if(data.type == 'messages') {
alert('HEY');
this.navCtrl.setRoot(TestpagePage);
}
} else {
alert('Untapped<br>' +
'User ID: ' + data.user_id +
'<br>User Name: ' + data.user_name +
'<br>Type: ' + data.type);
}
});
});
}
}
It will execute the 'HI' and 'HEY' alert inside the if(data.wasTapped) { but it seems like the this.navCtrl.setRoot('TestpagePage'); is not fired. I don't know why please help me!
So the problem have been solved.
Like #SurajRao suggested, instead of using fcm.onNotification().subscribe(function(data) { I followed his suggestion and updated my code to fcm.onNotification().subscribe((data) => { and it works.

Network Check and show Toast on Http Request

I am very new to ionic, currently working/learning with Ionic 2. I would like to show a toast when a user goes offline. I am currently able to do that as shown in my code below (toast shows whenever user goes offline). However what i would like to do is show the toast on http request (pull to refresh and infinite scroll). So that even when data is already loaded, the toast gets displayed when the user tries to pull to refresh on load more data through infinite scroll then they get notified that they are offline.
export class HomePage {
datas:any = [];
page:number =1;
connected: Subscription;
disconnected: Subscription;
constructor(private toast: ToastController, private network: Network, public navCtrl: NavController, private wpapi: Wpapi) {
this.getPosts();
}
displayNetworkUpdate(connectionState: string){
//let networkType = this.network.type
this.toast.create({
message: `You are currently ${connectionState}, please re connect your data`,
duration: 3000
}).present();
}
ionViewDidEnter() {
this.disconnected = this.network.onDisconnect().subscribe(data => {
console.log(data)
this.displayNetworkUpdate(data.type);
}, error => console.error(error));
}
getPosts() {
//this.page = '1';
//this.wpapi.index(this.page)
this.wpapi.index(1)
.subscribe(data => {
this.datas = data;
console.log(this.datas);
});
}
loadMore(infiniteScroll) {
this.page++;
this.wpapi.index( this.page ).subscribe( datas => {
// Loads posts from WordPress API
let length = datas["length"];
if( length === 0 ) {
infiniteScroll.complete();
return;
}
for (var i = length - 1; i >= 0; i--) {
this.datas.push( datas[i] );
}
infiniteScroll.complete();
});
}
doRefresh(refresher) {
this.wpapi.index(1)
.subscribe(data => {
this.datas = data;
refresher.complete();
});
}
ionViewWillLeave(){
this.connected.unsubscribe();
this.disconnected.unsubscribe();
}
}
This is what i'm doing. In my app.components i have the connection subscriber, beeing it offline or online, so if a user goes offline i save a conn boolean variable with false, if online i save true in my localStorage and present a toast saying it has gone offline (if gone online there's no need to present a toast).
network.onDisconnect().subscribe(() => {
storage.set('conn', false);
let conoff = ToastCtrl.create({
closeButtonText: 'Ok',
showCloseButton: true,
message: 'You're not connected to internet.',
position: 'top'
});
conoff.present();
});
You can create a service to do this, something like
import { Injectable } from '#angular/core';
import { Storage } from '#ionic/storage';
import { ToastController, Platform } from 'ionic-angular';
#Injectable()
export class Verificador {
constructor(public toast: ToastController, public storage: Storage, public platform: Platform) {
}
verifyConnection = (): Promise<boolean> => {
return new Promise<boolean>((res, rej) => {
this.storage.get('conn').then(conn => {
if (conn) {
res(true);
} else {
let t = this.toast.create({
closeButtonText: 'Ok',
showCloseButton: true,
message: 'You can't do this without internet.',
position: 'top'
});
t.present();
res(false);
}
})
})
}
}
So in every component, page entering, http call, you import that service/provider and call the verifyConnection function, if it returns true you just let the user do what it needs to do, if it's false the provider will show the toast.
import { ConnVerification} from '../../../providers/ConnVerification';
#IonicPage()
#Component({
selector: 'your-page',
templateUrl: 'your-page',
providers: [ConnVerification]
})
export class YourPage {
constructor(public verif: ConnVerification){}
myFunctionForSomething(){
this.verif.verifyConnection().then(conn =>{
if(conn){
// DO YOUR CODE
}
// NO NEED FOR ELSE SINCE IT'S HANDLED ON PROVIDER
})
}
}
Hope it helps :)

Resources