How to use Electron's <webview> within Angular2 app? - webview

I try to use Electon's webview tag inside my Angular2 app, but when I add the src attribute binded to an Angular2 variable, the following error occurs:
Can't bind to 'src' since it isn't a known native property
This is the index.html:
<head>
<!-- cut out stylings, metatags, etc. -->
<script src="../node_modules/zone.js/dist/zone.js"></script>
<script src="../node_modules/reflect-metadata/Reflect.js"></script>
<script src="../node_modules/systemjs/dist/system.src.js"></script>
<script src="systemjs.config.js"></script>
<script>
const electron = require('electron');
System.import('app').catch(function(err){ console.error(err); });
</script>
</head>
<body>
<MainComponent>Loading...</MainComponent>
</body>
This is the systemjs.config.js:
(function(global) {
// map tells the System loader where to look for things
var map = {
'app': 'angular',
'#angular': '../node_modules/#angular',
'angular2-in-memory-web-api': '../node_modules/angular2-in-memory-web-api',
'rxjs': '../node_modules/rxjs'
};
// packages tells the System loader how to load when no filename and/or no extension
var packages = {
'app': { main: 'main.js', defaultExtension: 'js' },
'rxjs': { defaultExtension: 'js' },
'angular2-in-memory-web-api': { defaultExtension: 'js' }
};
var ngPackageNames = [
'common',
'compiler',
'core',
'http',
'platform-browser',
'platform-browser-dynamic',
'router',
'router-deprecated',
'upgrade'
];
// Add package entries for angular packages
ngPackageNames.forEach(function(pkgName) {
packages['#angular/'+pkgName] = { main: pkgName + '.umd.js', defaultExtension: 'js' };
});
var config = {
map: map,
packages: packages
};
System.config(config);
})(this);
This is the Angular2 component template I (want to) use webview in:
<div class="stage-component component">
<webview *ngIf="iFrameUrl" src="{{iFrameUrl}}"></webview>
</div>
How can I introduce the webview element to Angular2?

If this appears, use "attr" before.
<webview *ngIf="iFrameUrl" attr.src="{{iFrameUrl}}"></webview>

That is strange. It sounds like you maybe have a version issue. You can try to use the loadUrl api instead and see if that helps.
<script>
onload = () => {
const webview = document.getElementById('foo');
webview.loadUrl('http://example.com')
</script>

Related

Electron - Uncaught ReferenceError: require is not defined

I have already searched in the others posts of stackflow with the same error, but aparently my problem is not about nodeIntegration parameter. Because, even the paramater of nodeIntegration is set true, i still get the undefined problem of require in the main-login.js file! PS: All files is in the same root and directory...
main.js
const { app, BrowserWindow, remote, ipcMain } = require("electron");
const path = require("path");
//Funcionalidade de criar window
function createWindow() {
const win = new BrowserWindow({
webPreferences: {
nodeIntegration: true,
preload: path.join(__dirname, "preload.js")
},
});
win.maximize();
win.loadFile("index.html");
}
//Chamada da funcionalidade de criação do window
app.whenReady().then(() => {
createWindow();
app.on("activate", function () {
if (BrowserWindow.getAllWindows().length === 0) createWindow();
});
});
//Fechamento do app quando todos os windows forem fechados
app.on("window-all-closed", function () {
if (process.platform !== "darwin") app.quit();
});
//Aprovação da validação do login
ipcMain.on("validation", function (e, item) {
console.log(item);
})
index.html
<!DOCTYPE html>
<html lang="en">
<head>...</head>
<body>
<div class="container-login100" style="background-image: url('images/pdv-login.jpg');">
...
<div class="container-login100-form-btn">
<button class="login100-form-btn">
Entrar
</button>
</div>
</div>
</div>
<!--===============================================================================================-->
<script src="vendor/jquery/jquery-3.2.1.min.js"></script>
...
<script src="vendor/countdowntime/countdowntime.js"></script>
<!--===============================================================================================-->
<script src="main-login.js"></script>
</body>
</html>
main-login.js
const { ipcRenderer } = require('electron');
(function ($) {
"use strict";
...
function hideValidate(input) {
var thisAlert = $(input).parent();
$(thisAlert).removeClass("alert-validate");
$(thisAlert).find(".btn-hide-validate").remove();
}
})(jQuery);

NativeScript WebView loading local resources in src document

I am loading a local html file as the src for a NativeScript WebView component. Contained within the html file are script tags which reference javascript files that are also local resources (bundled within the app). The html file loads into the WebView just fine, but the referenced script file (mylib.js) does not.
I suspect a pathing problem but I have tried almost every variation I can think of to no avail.
My project is actually a NativeScript-Vue project and is as follows:
App.vue
<template>
<Page #loaded="onPageLoaded">
<ActionBar title="Welcome to WebView"/>
<GridLayout>
<WebView ref="myWebView" row="0" col="0"
:src="filePath" #loadFinished="onWebViewLoaded" />
</GridLayout>
</Page>
</template>
<script>
import * as fs from "tns-core-modules/file-system"
import * as utils from "utils/utils"
export default {
data() {
return {
filePath: ''
}
},
methods: {
onPageLoaded () {
this.setLocalIndexFilePath()
},
onWebViewLoaded (event) {
if (event.error) {
console.log(error)
} else {
console.log('webview loaded')
}
},
setLocalIndexFilePath () {
const deviceName =
utils.ios.getter(UIDevice, UIDevice.currentDevice).name
// iPhone 6 is the name of my simulator
if (deviceName == 'iPhone 6') {
const webViewSRC =
encodeURI(`${fs.knownFolders.currentApp().path}/www/index.html`)
this.filePath = webViewSRC
console.log(webViewSRC)
} else {
this.filePath = "~/www/index.html"
}
}
}
}
</script>
index.html
<!doctype html>
<head>
<script src="./mylib.js" type="text/javascript"></script>
<script type="text/javascript">
function onBodyLoaded() {
var msg = document.getElementById('msg');
msg.insertAdjacentHTML('beforeend', '<br />body loaded!');
}
function onLocalButtonClicked() {
var msg = document.getElementById('msg');
msg.insertAdjacentHTML('beforeend', '<br />local: You clicked button!');
}
</script>
</head>
<html>
<body onload="onBodyLoaded()">
<Button onclick="onLocalButtonClicked()">Click Me</Button>
<Button onclick="onButtonClicked()">Click Me to test external js</Button>
<p id="msg">Debug:</p>
</body>
</html>
mylib.js
// This function never gets called
function onButtonClicked() {
var msg = document.getElementById('msg');
msg.insertAdjacentHTML('beforeend', '<br />external js file: You clicked button!');
}
webpack.config.sys
...
// Copy assets to out dir. Add your own globs as needed.
new CopyWebpackPlugin([
{ from: "fonts/**" },
{ from: "**/*.+(jpg|png)" },
{ from: "assets/**/*" },
{ from: "www/**/*" },
...
This is a known issue with iOS. There is a patch work you could try, I had implemented the same in Playground for a similar issue, its applicable for Vue too.

Custom JQuery Mobile Button

I'm using jQuery Mobile 1.3, and attempted to follow a tutorial in order to create my own custom widget.
I'm getting stuck on the very first step, and I'm not sure if I'm following the right example for the right version of jQuery mobile.
There is no error on the page, my element is just never enriched.
(function($) {
$.widget("mobile.target", $.mobile.button, {
/** Available options for the widget are specified here, along with default values. */
options: {
inline: false,
mode: "default",
height: 200
},
/** Mandatory method - automatically called by jQuery Mobile to initialise the widget. */
_create: function() {
var inputElement = this.element;
var opts = $.extend(this.options, inputElement.data("options"));
$(document).trigger("targetcreate");
inputElement.after("<button>" + inputElement.val() + "</button>");
},
/** Custom method to handle updates. */
_update: function() {
var inputElement = this.element;
var opts = $.extend(this.options, inputElement.data("options"));
$(document).trigger("targetupdate");
inputElement.siblings("button").text(inputElement.val());
},
/* Externally callable method to force a refresh of the widget. */
refresh: function() {
return this._update();
}
});
/* Handler which initialises all widget instances during page creation. */
$(document).bind("pagecreate", function(e) {
$(document).trigger("targetbeforecreate");
return $(":jqmData(role='target')", e.target).target();
});
})(jQuery);
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="https://code.jquery.com/mobile/1.3.2/jquery.mobile-1.3.2.min.css" />
<script src="https://code.jquery.com/jquery-1.9.1.min.js"></script>
<script src="https://code.jquery.com/mobile/1.3.2/jquery.mobile-1.3.2.min.js"></script>
</head>
<body>
<input type="button" data-role="target" value="inp1">
<input type="button" value="inp2">
<div data-role="target">div1</div>
<div type="button">div2</div>
</body>
</html>
(function($) {
$.widget("mobile.target", $.mobile.button, {
/** Available options for the widget are specified here, along with default values. */
options: {
inline: false,
mode: "default",
height: 200
},
/** Mandatory method - automatically called by jQuery Mobile to initialise the widget. */
_create: function() {
var inputElement = this.element;
var opts = $.extend(this.options, inputElement.data("options"));
$(document).trigger("targetcreate");
inputElement.after("<button>" + inputElement.val() + "</button>");
},
/** Custom method to handle updates. */
_update: function() {
var inputElement = this.element;
var opts = $.extend(this.options, inputElement.data("options"));
$(document).trigger("targetupdate");
inputElement.siblings("button").text(inputElement.val());
},
/* Externally callable method to force a refresh of the widget. */
refresh: function() {
return this._update();
}
});
/* Handler which initialises all widget instances during page creation. */
$(document).bind("pagecreate", function(e) {
$(document).trigger("targetbeforecreate");
return $(":jqmData(role='target')", e.target).target();
});
})(jQuery);
Expected output was a custom JQueryMobile button that inherits from the JQueryMobile button. Not just a tiny html5 button in a div. e.g. Div1 rendering the same as Div2 but with customized changes made.
You are trying to get an input element in jQuery code. But you defined a div element in the HTML page.
That is the problem. Change it to input.
Check the below code
The tutorial you followed states that only use the :jqmData if you didn't use the HTML5 data attribute. Remove it
(function($) {
$.widget("mobile.target", $.mobile.widget, {
options: {
inline: false,
mode: "default",
height: 200
},
_create: function() {
var inputElement = this.element;
var opts = $.extend(this.options, inputElement.data("options"));
$(document).trigger("targetcreate");
inputElement.after("<button>"+inputElement.val()+"</button>");
},
_update: function() {
var inputElement = this.element;
var opts = $.extend(this.options, inputElement.data("options"));
$(document).trigger("targetupdate");
inputElement.siblings("button").text(inputElement.val());
},
refresh: function() {
return this._update();
}
});
$(document).bind("pagecreate", function(e) {
$(document).trigger("mywidgetbeforecreate");
return $("[role='target']", e.target).target();
});
})(jQuery);
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="https://code.jquery.com/mobile/1.3.2/jquery.mobile-1.3.2.min.css" />
<script src="https://code.jquery.com/jquery-1.9.1.min.js"></script>
<script src="https://code.jquery.com/mobile/1.3.2/jquery.mobile-1.3.2.min.js"></script>
</head>
<body>
<input type="button" data-role="target" value="inp1">
<input type="button" value="inp2">
<div type="button" data-role="target">div1</div>
<div type="button">div2</div>
</body>
</html>

Why does using requirejs 2 stop my backbone / jQuery mobile app working?

I have a very simple proof of concept app built with jQuery Mobile, Backbone.js, and require.js.
I am using Backbone's router, and I have jQuery Mobile's routing disabled. It works perfectly.
I am using require.js 1.04. However: when I use requirejs 2.1.14, then I can't seem to disable jQuery Mobile's routing, and hence Backbone's routing stops working. Can't figure it out.
The following code works if I remove jQuery mobile, but stops working if I put jQuery mobile back in. Similarly, it will work with Require.js 1.0.4, but not with require.js 2.1.14:
index.html:
<html>
<body>
Click Here
<script data-main="main" src="require.js"></script>
</body>
</html>
main.js
require.config({
paths : {
backbone : 'libraries/backbone/backbone',
underscore : 'libraries/underscore/underscore',
jquery : 'libraries/jquery/jquery-1.7.1',
jqm : 'libraries/jquery.mobile/jquery.mobile',
router: 'router'
},
shim: {
jqm: {
exports: 'jqm',
deps: ['jquery']
},
underscore: {
exports: 'underscore'
},
backbone: {
exports: 'backbone',
deps: ['jquery', 'underscore']
}
}
});
require(
['jquery', 'jqm', 'underscore', 'backbone', 'router'],
function ($, $$, underscore, Backbone, router) {
$.mobile.ajaxEnabled = false;
$.mobile.linkBindingEnabled = false;
$.mobile.hashListeningEnabled = false;
$.mobile.pushStateEnabled = false;
$.mobile.changePage.defaults.changeHash = false;
router.init();
});
router.js
define(['jquery', 'jqm', 'underscore', 'backbone'],
function($, $$, _, Backbone) {
var init = function () {
$.mobile.ajaxEnabled = false;
$.mobile.linkBindingEnabled = false;
$.mobile.hashListeningEnabled = false;
$.mobile.pushStateEnabled = false;
$.mobile.changePage.defaults.changeHash = false;
var AppRouter = Backbone.Router.extend({
routes: {
"posts/:id" : "getSomePost",
"*action": "defaultRoute"
},
getSomePost: function(id) {
alert( "Get post number " + id );
},
defaultRoute: function( actions ){
console.log('Action: ' + actions );
}
});
// Instantiate the backbone router
var app_router = new AppRouter();
// Start Backbone history
Backbone.history.start();
};
return { init : init };
});
This problem is seriously baking my noodle!!
When I load up the app, I see a link saying "Click here". When the app uses requirejs-1.0.4 (or without jquery mobile) it works, I get an alert saying "get post number 1", and the URL looks like:
http://myapp.dev/src/#posts/1
but when using requirejs-2.1.14 and jQuery Mobile, I the URL quickly changes to this:
http://myapp.dev/src/posts/1
and nothing happens.
Help!
I finally found the answer to this problem. The issue is the timing of jQuery Mobile configuration. According to the jQuery Mobile docs:
Because the mobileinit event is triggered immediately, you'll need to
bind your event handler before jQuery Mobile is loaded
So I rewrote main.js like so:
require.config({
paths : {
backbone : 'libraries/backbone/backbone',
underscore : 'libraries/underscore/underscore',
jquery : 'libraries/jquery/jquery-1.7.1',
jqmconfig : 'jquerymobile.config',
jqm : 'libraries/jquery.mobile/jquery.mobile',
router: 'router'
},
shim: {
jqm: {
exports: 'jqm',
deps: ['jquery', 'jqmconfig']
},
underscore: {
exports: 'underscore'
},
backbone: {
exports: 'backbone',
deps: ['jquery', 'jqm', 'underscore']
}
}
});
require(
['jquery', 'backbone', 'jqmconfig', 'jqm', 'router'],
function ($, Backbone, jqmconfig, $$, router) {
router.init();
});
And added a new file called jquerymobile.config.js:
define(['jquery'], function ($) {
$(document).on('mobileinit', function () {
// Prevents all anchor click handling
$.mobile.linkBindingEnabled = false
// Disabling this will prevent jQuery Mobile from handling hash changes
$.mobile.hashListeningEnabled = false
$.mobile.ajaxEnabled = false;
$.mobile.pushStateEnabled = false;
});
});
This code fires after jQuery has loaded, but BEFORE jQuery Mobile has loaded, which is the key!
For reference, this is the blog post that helped me figure it out:
http://www.justinmccandless.com/blog/Yeoman%2C+Requirejs%2C+jQuery+Mobile%2C+Backbone%2C+and+a+Lot+of+Config+Problems

Openlayers + Require.js + Backbone.js + jQueryMobile -> Tiles not loading

I have set up a project that uses require.js, backbone.js, openlayers (mobile single file build) and jquery mobile.
Now I have some issues displaying the map correctly, because no tiles are loading. I have figured out how to load the openlayers api with the require.js shim parameter:
shim: {
"backbone": {
"deps": [ "underscore", "jquery" ],
"exports": "Backbone"
},
"openlayers": {
"exports": "OpenLayers"
}
}
In the MapView.js file I create a new openlayers map:
define([ "jquery", "backbone", "openlayers" ], function( $, Backbone, OpenLayers ) {
var MapView = Backbone.View.extend( {
// The View Constructor
initialize: function() {
console.log(3);
var mapOptions = {
div: this.el,
maxExtent: new OpenLayers.Bounds(-174,18.4,-63.5,71),
maxResolution: 0.25,
projection: "EPSG:102100",
theme: "/css/theme/default/style.css",
layers: [
new OpenLayers.Layer.OSM("OpenStreetMap", null, {
transitionEffect: 'resize'
})
]};
this.map = new OpenLayers.Map( mapOptions );
},
render: function() {
console.log(4);
}
} );
return MapView;
} );
Now the map works partly. I can see the Zoom Buttons which are added by openlayers at the top-left of the map, but no Tiles are loaded. Firebug told me, that there isn't even a request for the tiles.
At the moment I have no clue whats the problem might be.
For completetion this is my backbone router:
define([ "jquery", "backbone", "../models/Map", "../views/Map" ], function( $, Backbone, MapModel, MapView ) {
var Router = Backbone.Router.extend( {
initialize: function() {
console.log(2);
this.mapView = new MapView( { el: "#mapView" } );
Backbone.history.start();
},
// Backbone.js Routes
routes: {
"": "home",
},
// Home method
home: function() {
console.log(0);
$.mobile.changePage( "#map" , { reverse: false, changeHash: false } );
},
});
return Router;
} );
and the Page html
<!doctype html>
<html>
<head>
<link type="text/css" rel="stylesheet" href="/css/jquerymobile.css" />
<script src="/js/libs/require-min.js" data-main="/js/mobile"></script>
<style>
#mapView {
height: 500px;
width: 500px;
}
</style>
</head>
<body>
<div id="map" data-role="page" data-title="Map">
<div data-role="header">
<h1>Map</h1>
</div><!-- /header -->
<div data-role="content">
<div id="mapView"></div>
</div><!-- /content -->
</div>
</body>
</html>
Any ideas?
I figured it out now. All I had to do is add this.map.zoomToMaxExtent();. For some reason without that the map was not able to calculate the correct visible extent for the tiles.

Resources