WKWebview run JavaScript - ios

I have an app with WKWebview loading the site.
On the site I have the next HTML code:
div class="uk-offcanvas-bar z_page_padding_mob_top"
I need to find all elements "uk-offcanvas-bar" and run "z_page_padding_mob_top" function on them.
How can I implement running this script in WKWebview ?

let script = "var x = document.getElementsByClassName('uk-offcanvas-bar'); for (var i = 0; i < x.length; i++) { x[i].classList.add('z_page_padding_mob_top'); }"
webView.evaluateJavaScript(script) { (result, error) in
if let result = result {
print(result)
}
}
This code is worked for me.

Related

Printing using ngx-extended-pdf-viewer on iOS and Mobile Safari or Chrome

I have an Angular 7 app that is using ngx-extended-pdf-viewer to render a PDF that I get as a byte array from the web.api. I have no issues rendering the PDF or even printing it from any desktop application. ngx-extended-pdf-viewer as a print button built right in. However, when trying to print from Safari on an iPhone (iOS 12) it only prints a blank page with the url at the bottom. The actual PDF does not print. With Chrome on iOS it doesn't do anything that I can see. I am pretty new to Angular and actually to mobile web development, so perhaps lack of knowledge is getting me. The PDF viewer is in a mat-tab, so not sure if maybe that is causing some issues??
I have tried other packages, but they all seem to be based on the same pdf.js code from Mozilla. Also this is the only one I've found so far that has a print. I was thinking about perhaps trying pdf.js outside of an npm package, but so far have not found solid directions on getting this to work in Angular. I'm sure it will, but all directions I have found seem to omit details. Such as, put this code in your app. They just fail to say where in the app.
From the web.api:
[HttpPost("GetPdfBytes/{PdfId}")]
public ActionResult<byte[]> GetPdfBytesId([FromBody]int id)
{
string exactPath = string.Empty;
if (id == 1)
{
exactPath = Path.GetFullPath("pdf-test.pdf");
}
else if (id == 2)
{
exactPath = Path.GetFullPath("DPP.pdf");
}
else if (id == 3)
{
exactPath = Path.GetFullPath("Request.pdf");
}
else
{
exactPath = Path.GetFullPath("Emergency Issue.pdf");
}
byte[] bytes = System.IO.File.ReadAllBytes(exactPath);
return Ok(bytes);
}
The HTML:
<mat-tab label="PDF">
<ng-template matTabContent>
<ngx-extended-pdf-viewer *ngIf="visible[2]" id="pdf3" [src]="pdfSrc3" useBrowserLocale="true" delayFirstView="1000" showSidebarButton="false"
showOpenFileButton="false" >
</ngx-extended-pdf-viewer>
</ng-template>
</mat-tab>
TypeScript:
getPDFBytesId(id: string) {
this.getPDFFromServicePdfBytesId(Number(id)).subscribe(
(data: any) => {
this.pdfSrc3 = this.convertDataURIToBinary(data);
},
error => {
console.log(error);
}
);
}
// hits the web.api
getPDFFromServicePdfBytesId(id: number): Observable<any> {
const body = id;
return this.http.post<any>('http://localhost:5000/api/values/GetPdfBytes/' + id, body);
}
// converts what we got back to a Uint8Array which is used by the viewer
convertDataURIToBinary(dataURI: string) {
const raw = window.atob(dataURI);
const rawLength = raw.length;
const array = new Uint8Array(new ArrayBuffer(rawLength));
for (let i = 0; i < rawLength; i++) {
array[i] = raw.charCodeAt(i);
}
return array;
}

SELECT statement no longer working after installing cordova-plugin-ionic-webview

I was trying to fix some performance issues in my ionic hybrid app when using AWS cognito which requires installing cordova-plugin-ionic-webview. However, after installing this plugin, my SELECT statement is no longer working - it is now returning no records found. Here is the statement:
dbAccess.SelectGoodsReceiptDetail = function SelectGoodsReceiptDetail(goodsreceipt) {
var resultData = {};
// Select Multiple Items
return $q(function(resolve, reject) {db.executeSql("SELECT * FROM goodsreceiptdetailview WHERE goodsReceiptKey LIKE ?", [ goodsreceipt.header.goodsReceiptKey] , function(rs) {
resultData.data = [{}];
if (rs.rows.length > 0) {
if (rs.rows.item) {
for (i=0;i<rs.rows.length; i++) {
resultData.data[i] = rs.rows.item(i);
}
resultData.exist = true;
}
} else {
// no item found
resultData.exist = false;
}
resolve(resultData);
}, function(error) {
resultData.data = [{}];
resultData.exist = false;
resultData.failed = true;
resolve(resultData);
})
});
}
The variable goodsreceipt.header.goodsReceiptKey in an integer. I have read in the release notes for the cordova sqlite plugin that whole numbers are treated as REAL values when using WKWebView while it is being treated as INT on UIWebView here. Could this be causing the problem? How can I fix this with WKWebView?
I was able to fix this by converting the INT to string.

Get a list of pictures and upload them with CasperJS?

I need some help with my CasperJS script.
I don't know how can I get all my pictures as an array from the current folder.
And how to loop to insert each one in the correct input.
Mmmh, difficult to explain so there is my starting code.
I put comment where I have problem.
var casper = require('casper').create();
casper.start('http://imgchili.net/', function() {
// Get a list with all the picture from the current folder.
// For each picture, click this button.
this.mouseEvent('click', 'input.button1:nth-child(6)');
this.fillSelectors('form#upload_form', {
// Another loop here.
'.grey > input:nth-child(2)': /* First picture */,
'.grey > input:nth-child(4)': /* Second picture */,
'.grey > input:nth-child(6)': /* Third picture */
}, true);
casper.capture('captureTest.png');
});
// 8s can be too low if I have a lot of pictures!
casper.wait(8000, function() {
casper.capture('captureResult.png');
})
casper.then(function() {
this.echo(this.fetchText('textarea.input_field:nth-child(11)'));
})
casper.run();
EDIT:
Thanks it helps me a lot. But I have problem to loop the inputs.
var fs = require('fs'),
casper = require('casper').create(),
myImages = fs.list(fs.workingDirectory + '/img');
casper.start('http://imgchili.net/', function() {
// For each image, click to add a new upload input.
// Begin with 2 because 0 = "."" and 1 = "..".
for (var i = 2; i < myImages.length; i++) {
this.mouseEvent('click', 'input.button1:nth-child(6)');
}
// It doesn't work and show no error...
for (var i = 2; i < myImages.length; i++) {
j = i*2;
input = '.grey > input:nth-child(' + j + ')';
this.fillSelectors('form#upload_form', {
input : '/img/' + myImages[i],
}, false);
// Even this part doesn't work
console.log('i = ' + i + ' & imgName = ' + myImages[i]);
}
});
casper.then(function() {
casper.capture('result.png');
});
casper.run();
You can use PhantomJS file system to get your current folder files. Here is the API Documentation.
The following gets your current folders files, and then filters all .png's into a new array. You can then use a loop to click the button for each image. You will have to alter / add your own code because this does not accomplish the upload task. This will should help you though.
// vars
var fs = require('fs'); // reference to phantomJS file system
var myFolder = fs.list(fs.workingDirectory); // gets all files in current folder
var myImages = []; // only images from current folder
var url = 'http://imgchili.net/'; // starting url
var fileType = '.png'; // image file type to filter by
casper.then(function() {
// create array of just images
for (var i = 0; i < myFolder.length; i++) {
if (myFolder[i].indexOf(fileType) != -1) {
myImages.push(myFolder[i]);
}
}
// click for each image
for (i = 0; i < myImages.length; i++) {
this.mouseEvent('click', 'input.button1:nth-child(6)');
}
});
// wait for images to be uploaded
// set timeout or defaults to caspers step timeout
casper.waitForSelector('#page_body', function() {
casper.capture('captureResult.png');
}, 15000);

Titanium WebView.toImage on coverFlowView

A have several views with WebViews on them. I need to make it in a coverFlowView. For that i make my views toImage, to put after on the coverFlow, but the issue is that i get images with webView not loaded... I tried to make setTimeout, but it doesn't help.
var cover = Titanium.UI.iOS.createCoverFlowView({
images: forflowImages
});
for (var k = start; k < cData.length; k++) {
r = Ti.UI.createView({});
for (var j = 0; j < child.objects.length; j++) {
tmp = Ti.UI.createWebView({
left : 10,
top : 10,
right : 10,
bottom : 10,
width : Ti.UI.FILL,
height : Ti.UI.SIZE,
willHandleTouches: true,
backgroundColor : '#fff2df',
});
tmp.html = obj.html;
no.add(tmp);
r.add(no);
}
}
r.addEventListener("load", function(e) {
blob = r.toImage();
});
forflowImages.push(blob);
}
cover.setImages(forflowImages);
With this code, coverFlowView doesn't have any views.
setTimeout(function() {
blob = r.toImage();
}, 500);
Also doesn't help, i have activity indicator on the page saved, content seems didn't have time to load before toImage function acted.
You are ordering things the wrong way, and you have multiple syntax errors, also you are listeneing for the load event on the wrong type of view, you shold be listeneing on the WebView, try this instead:
var forflowImages = [];
var container = // This should already be in the view stack somewhere
var cover = Titanium.UI.iOS.createCoverFlowView();
function loadListener(e) {
forflowImages.push(e.source.toImage());
if(forFlowImages.length == child.objects.length) {
// We have all the images for cover flow
cover.setImages(forflowImages);
}
}
var containerView = Ti.UI.createView();
for (var j = 0; j < child.objects.length; j++) {
var tmp = Ti.UI.createWebView({html : obj.html);
tmp.addEventListener("load", loadListener);
container.add(tmp);
tmp.repaint();
}
I removed some of your code that was syntactically incorrect and trimmed it down so it would be easy to understand. All this code does is add an event listener that handles the conversion of a webview to an image.

PrettyPhoto annd youtube videos overlay

I have a webpage with prettyPhoto and a youtube video inside the web page.
With jquery I do:
$("#youtubevideo embed").attr("wmode", "opaque");
also tried $("#youtubevideo embed").attr("wmode", "transparent");
In firefox image is over the youtube video, but the corners of pretty photo are missing. Not really missing because if I scroll up ad down they are shown. But still they don't appear correctly.
In Chrome video is still on top of the images :( Is there a way to fix this? Thanks
after 2 days of searching the web for the answer i've found a pure JS function that fix it in all browsers!
there you go:
function fix_flash() {
// loop through every embed tag on the site
var embeds = document.getElementsByTagName('embed');
for (i = 0; i < embeds.length; i++) {
embed = embeds[i];
var new_embed;
// everything but Firefox & Konqueror
if (embed.outerHTML) {
var html = embed.outerHTML;
// replace an existing wmode parameter
if (html.match(/wmode\s*=\s*('|")[a-zA-Z]+('|")/i))
new_embed = html.replace(/wmode\s*=\s*('|")window('|")/i, "wmode='transparent'");
// add a new wmode parameter
else
new_embed = html.replace(/<embed\s/i, "<embed wmode='transparent' ");
// replace the old embed object with the fixed version
embed.insertAdjacentHTML('beforeBegin', new_embed);
embed.parentNode.removeChild(embed);
} else {
// cloneNode is buggy in some versions of Safari & Opera, but works fine in FF
new_embed = embed.cloneNode(true);
if (!new_embed.getAttribute('wmode') || new_embed.getAttribute('wmode').toLowerCase() == 'window')
new_embed.setAttribute('wmode', 'transparent');
embed.parentNode.replaceChild(new_embed, embed);
}
}
// loop through every object tag on the site
var objects = document.getElementsByTagName('object');
for (i = 0; i < objects.length; i++) {
object = objects[i];
var new_object;
// object is an IE specific tag so we can use outerHTML here
if (object.outerHTML) {
var html = object.outerHTML;
// replace an existing wmode parameter
if (html.match(/<param\s+name\s*=\s*('|")wmode('|")\s+value\s*=\s*('|")[a-zA-Z]+('|")\s*\/?\>/i))
new_object = html.replace(/<param\s+name\s*=\s*('|")wmode('|")\s+value\s*=\s*('|")window('|")\s*\/?\>/i, "<param name='wmode' value='transparent' />");
// add a new wmode parameter
else
new_object = html.replace(/<\/object\>/i, "<param name='wmode' value='transparent' />\n</object>");
// loop through each of the param tags
var children = object.childNodes;
for (j = 0; j < children.length; j++) {
try {
if (children[j] != null) {
var theName = children[j].getAttribute('name');
if (theName != null && theName.match(/flashvars/i)) {
new_object = new_object.replace(/<param\s+name\s*=\s*('|")flashvars('|")\s+value\s*=\s*('|")[^'"]*('|")\s*\/?\>/i, "<param name='flashvars' value='" + children[j].getAttribute('value') + "' />");
}
}
}
catch (err) {
}
}
// replace the old embed object with the fixed versiony
object.insertAdjacentHTML('beforeBegin', new_object);
object.parentNode.removeChild(object);
}
}
}
now you can just run in when the page loads with jQuery:
$(document).ready(function () {
fix_flash();
}
Also you can add ?wmode=transparent to each youtube link
So if you have code like:
<iframe src="http://www.youtube.com/embed/aoZbiS20HGI">
</iframe>
You need to change it to:
<iframe src="http://www.youtube.com/embed/aoZbiS20HGI?wmode=transparent">
</iframe>

Resources