Print plugin phonegap - javascript

Hi i'm quite confused on some parts of the Print Plugin or the Phonegap plugin. See i was able to implement the code even created my own plugin but i was no returning values from objective-c (xcode) back to javascript so it was safe to say that it was easy to understand.
On this code:
https://github.com/phonegap/phonegap-plugins/blob/master/iPhone/PrintPlugin/PrintPlugin.js
On this block of code:
PrintPlugin.prototype.callbackMap = {};
PrintPlugin.prototype.callbackIdx = 0;
PrintPlugin.prototype.print = function(printHTML, success, fail, options) {
if (typeof printHTML != 'string'){
console.log("Print function requires an HTML string. Not an object");
return;
}
//var printHTML = "";
var dialogLeftPos = 0;
var dialogTopPos = 0;
if (options){
if (options.dialogOffset){
if (options.dialogOffset.left){
dialogLeftPos = options.dialogOffset.left;
if (isNaN(dialogLeftPos)){
dialogLeftPos = 0;
}
}
if (options.dialogOffset.top){
dialogTopPos = options.dialogOffset.top;
if (isNaN(dialogTopPos)){
dialogTopPos = 0;
}
}
}
}
var key = 'print' + this.callbackIdx++;
window.plugins.printPlugin.callbackMap[key] = {
success: function(result) {
delete window.plugins.printPlugin.callbackMap[key];
success(result);
},
fail: function(result) {
delete window.plugins.printPlugin.callbackMap[key];
fail(result);
},
};
var callbackPrefix = 'window.plugins.printPlugin.callbackMap.' + key;
return PhoneGap.exec("PrintPlugin.print", printHTML, callbackPrefix + '.success', callbackPrefix + '.fail', dialogLeftPos, dialogTopPos);
};
Especially this lines of code:
PrintPlugin.prototype.callbackMap = {};
PrintPlugin.prototype.callbackIdx = 0;
I'm confused by what that two lines of code does and why it is somehow important to incorporate or follow when you want to return values from xcode to javascript (NOTE: by me saying why it is somehow important to incorporate or follow when you want to return values from xcode to javascript i'm saying this based on what I've understood so far)
Can somebody explain how the two lines of code works and what are their purpose? Thank you.

Related

Storing items as cookies, works perfectly fine on a normal browser, but on a native device browser there are implications

I am creating a website for a client at the moment, we decided an easy way to store "items" which will be passed down to a subdomain from the root would be to store them as cookies. This works perfectly fine in a normal browser, yet when I tested it on a native device browser it didn't work as smoothly. I am wondering where some of these problems may have been coming from and hoping you wonderful developers can lend a man a hand.
The idea is that on the frontend when a "Your Order" side drawer is pressed, a function runs grabbing the cookies and then sorts them into their specified content area's -> Downloadable Content, Requested Material and Bespoke Content. I have created two separate functions for this, one that was the original working piece and another more tailored and "good practice".
Tried having the "Value" of the cookie containing the values that need to be stored such as, [itemname],[itemlocation], [itemdescription], [itemtype].
The second function stores the item data in an object, the object is then JSON.stringified and iterated over in a for loop. This is then taken out of a string with JSON.parse() and further iterated over in an .each() iterating over the index(key) and val(value).
FIRST FUNCTION:
$('section#review-downloads a.toggle-btn').bind('click tap', function() {
let cookies;
let itemSplit;
var section = $('section#review-downloads');
if(section.hasClass('active')) {
section.removeClass('active');
setTimeout(function() {
$('section#review-downloads .selected-items div').find('p').remove();
}, 900);
} else {
section.addClass('active');
$.each(document.cookie.split(';'), function() {
cookies = this.split('=');
let trimId = cookies[0].trim();
vals = cookies[1].replace(/[\])}[{(]/g, '');
if(!(cookies[0] === "envFilter")) {
$.each(vals.split('[ ]'),function() {
itemSplit = this.split(',');
let itemId = trimId;
let itemName = itemSplit[0];
let itemUrl = itemSplit[1];
let itemType = itemSplit[2];
let itemDesc = itemSplit[3];
if(itemType === ' Downloadable Content ') {
$('<p id="selected-item-'+itemId+'"><strong>'+itemName+'</strong>'+itemDesc+'</p>').appendTo('section#review-downloads .review-container .selected-items .downloadable-content');
} else if (itemType === ' Requested Materials ') {
$('<p id="selected-item"><strong>'+itemName+'</strong>'+itemDesc+'</p>').appendTo('section#review-downloads .review-container .selected-items .requested-material');
} else if (itemType === ' Bespoke Content ') {
$('<p id="selected-item"><strong>'+itemName+'</strong>'+itemDesc+'</p>').appendTo('section#review-downloads .review-container .selected-items .bespoke-content');
}
});
};
});
}
return false;
});
THE SECOND FUNCTION (best practice)
$('div.support-item-wrapper div.order-add').bind('click tap', function() {
let id = $(this).data('id');
let name = $(this).data('title');
let file = $(this).data('file');
let type = $(this).data('type');
let desc = $(this).data('description').replace(/(\r\n|\n|\r)/gm, "");
let url = $(this).data('url');
let cookieVal = {
name: name,
file: file,
type: type,
desc: desc,
url: url
};
let string = JSON.stringify(cookieVal);
setCookie('product-'+id, string, 1);
});
$('section#review-downloads a.toggle-btn').bind('click tap', function() {
var section = $('section#review-downloads');
if(section.hasClass('active')) {
section.removeClass('active');
} else {
section.addClass('active');
let decoded_user_product;
cookie_values = document.cookie.split(';');
for(i = 0; i < cookie_values.length; i++) {
cookie_split = cookie_values[i].split("=");
cookie_key = cookie_split[0].trim();
cookie_value = cookie_split[1].trim();
// console.log(cookie_value);
if(cookie_key != "envFilter") {
decoded_user_product = JSON.parse(cookie_value);
}
$.each(decoded_user_product, function(index, val) {
// console.log("index:" + index + "& val:" + val);
if(index === "name") {
console.log(val);
} else if (index === "type") {
console.log(val);
} else if (index === "desc") {
console.log(val);
}
});
}
// console.log(decoded_user_product);
};
});
On Desktop, the results are perfectly fine. Each item is easily console.log()'able and has been easily sorted in the FIRST FUNCTION.
On Mobile, the same results were as to be expected. But after realising it hadn't worked I used chrome://inspect along with a lot of console.logs to come to the conclusion that I may be too inexperienced to understand what parts of my code are unable to run on a native browser.

How to properly use Parse / Promise?

I am writing some JavaScript codes using Parse.com.
To be honest, I have been reading how to use Promise and done lots of research but cannot still figure out how to use it properly..
Here is a scenario:
I have two tables (objects) called Client and InvoiceHeader
Client can have multiple InvoiceHeaders.
InvoiceHeader has a column called "Amount" and I want a total amount of each client's InvoiceHeaders.
For example, if Client A has two InvoiceHeaders with amount 30 and 20 and Client B has got nothing, the result I want to see in tempArray is '50, 0'.
However, with the following codes, it looks like it's random. I mean sometimes the tempArray got '50, 50' or "50, 0". I suspect it is due to the wrong usage of Promise.
Please help me. I have been looking into the codes and stuck for a few days.
$(document).ready(function() {
var client = Parse.Object.extend("Client");
var query = new Parse.Query(client);
var tempArray = [];
query.find().then(function(objects) {
return objects;
}).then(function (objects) {
var promises = [];
var totalForHeader = 0;
objects.forEach(function(object) {
totalForHeader = 0;
var invoiceHeader = Parse.Object.extend('InvoiceHeader');
var queryForInvoiceHeader = new Parse.Query(invoiceHeader);
queryForInvoiceHeader.equalTo('headerClient', object);
var prom = queryForInvoiceHeader.find().then(function(headers) {
headers.forEach(function(header) {
totalForHeader += totalForHeader +
parseFloat(header.get('headerOutstandingAmount'));
});
tempArray.push(totalForHeader);
});
promises.push(prom);
});
return Parse.Promise.when.apply(Parse.Promise, promises);
}).then(function () {
// after all of above jobs are done, do something here...
});
} );
Assuming Parse.com's Promise class follows the A+ spec, and I understood which bits you wanted to end up where, this ought to work:
$(document).ready(function() {
var clientClass = Parse.Object.extend("Client");
var clientQuery = new Parse.Query(clientClass);
clientQuery.find().then(function(clients) {
var totalPromises = [];
clients.forEach(function(client) {
var invoiceHeaderClass = Parse.Object.extend('InvoiceHeader');
var invoiceHeaderQuery = new Parse.Query(invoiceHeaderClass);
invoiceHeaderQuery.equalTo('headerClient', client);
var totalPromise = invoiceHeaderQuery.find().then(function(invoiceHeaders) {
var totalForHeader = 0;
invoiceHeaders.forEach(function(invoiceHeader) {
totalForHeader += parseFloat(invoiceHeader.get('headerOutstandingAmount'));
});
return totalForHeader;
});
totalPromises.push(totalPromise);
});
return Parse.Promise.when(totalPromises);
}).then(function(totals) {
// here you can use the `totals` array.
});
});

Parse values from HTML element using Google App Script?

I am trying to parse HTML element by class on Google Sites, my code is:
function doGet(){
var html = UrlFetchApp.fetch ('http://indicadoresdeldia.cl/').getContentText();
var doc = XmlService.parse(html);
var html = doc.getRootElement();
var menu = getElementsByClassName(html, 'span3 utm')[0];
var output = XmlService.getRawFormat().format(menu);
return HtmlService.createHtmlOutput(output);
}
Ween i run the code appear the nexte error message ReferenceError: "getElementsByClassName" is not defined.
i am trying to deploy the example for the next page: https://sites.google.com/site/scriptsexamples/learn-by-example/parsing-html
Any ideas?
THanks in advance for your help.
According to that site, you should directly copy those functions to your project (source code available there) and then call them. That would alleviate each and every one of your problems.
Source: https://sites.google.com/site/scriptsexamples/learn-by-example/parsing-html
function getElementsByClassName(element, classToFind) {
var data = [];
var descendants = element.getDescendants();
descendants.push(element);
for(i in descendants) {
var elt = descendants[i].asElement();
if(elt != null) {
var classes = elt.getAttribute('class');
if(classes != null) {
classes = classes.getValue();
if(classes == classToFind) data.push(elt);
else {
classes = classes.split(' ');
for(j in classes) {
if(classes[j] == classToFind) {
data.push(elt);
break;
}
}
}
}
}
}
return data;
}

Simpy cannot iterate over javascript object?

I have scoured the other question/answer for this and implemented everything and I still cannot access the values of the object. Here's the code I am using:
function apply_voucher(voucher) {
var dates = $.parseJSON($("[name='dates']").val());
var voucher_yes_no = new Array();
var voucher_reduction = new Array();
if(voucher.length > 0)
{
$.each(dates, function(room_id, these_dates) {
$.post('/multiroom/check_voucher/'+voucher+'/'+room_id, function(result) {
if(result.result == 'ok') {
voucher_yes_no.push('yes');
voucher_reduction.push(result.voucher_reduction);
} else {
voucher_yes_no.push('no');
}
}, 'json');
});
// check if there are any yes's in the array
if('yes' in voucher_yes_no) {
console.log("no yes's");
} else {
console.log(voucher_reduction);
console.log(typeof voucher_reduction);
for (var prop in voucher_reduction) {
console.log(prop);
console.log(voucher_reduction[prop]);
if (voucher_reduction.hasOwnProperty(prop)) {
console.log("prop: " + prop + " value: " + voucher_reduction[prop]);
}
}
}
}
}
Apologies for the constant console logging - I'm just trying to track everything to make sure it's all doing what it should. The console output I get from this is below:
...which shows the object containing one value, "1.01" and my console.log of the typeof it to make sure it is actually an object (as I thought I was going mad at one point). After this there is nothing from inside the for-in loop. I have tried jquery's $.each() also to no avail. I can't understand why nothing I'm trying is working!
It does not work because the Ajax call is asynchronous!
You are reading the values BEFORE it is populated!
Move the code in and watch it magically start working since it will run after you actually populate the Array!
function apply_voucher(voucher) {
var room_id = "169";
var dates = $.parseJSON($("[name='dates']").val());
var voucher_reduction = new Array();
$.post('/multiroom/check_voucher/'+voucher+'/'+room_id, function(result) {
if(result.result == 'ok') {
voucher_reduction.push(result.voucher_reduction);
}
console.log(voucher_reduction);
console.log(typeof voucher_reduction);
for (var prop in voucher_reduction) {
console.log(prop);
console.log(voucher_reduction[prop]);
if (voucher_reduction.hasOwnProperty(prop)) {
console.log("prop: " + prop + " value: " + voucher_reduction[prop]);
}
}
}, 'json');
}
From what it looks like, you plan on making that Ajax call in a loop. For this you need to wait for all of the requests to be done. You need to use when() and then(). It is answered in another question: https://stackoverflow.com/a/9865124/14104
Just to say for future viewers that changing the way I did this to use proper deferred objects and promises, which blew my head up for a while, but I got there! Thanks for all the help, particularly #epascarello for pointing me in the right direction :) As soon as I started doing it this way the arrays began behaving like arrays again as well, hooray!
Here's the final code:
function apply_voucher(voucher) {
var booking_id = $("[name='booking_id']").val();
var dates = $.parseJSON($("[name='dates']").val());
if(voucher.length > 0) {
var data = []; // the ids coming back from serviceA
var deferredA = blah(data, voucher, dates); // has to add the ids to data
deferredA.done(function() { // if blah successful...
var voucher_yes_no = data[0];
var voucher_reduction = data[1];
if(voucher_yes_no.indexOf("yes") !== -1)
{
console.log("at least one yes!");
// change value of voucher_reduction field
var reduction_total = 0;
for(var i = 0; i < voucher_reduction.length; i++) {
reduction_total += voucher_reduction[i];
}
console.log(reduction_total);
}
else
{
console.log("there are no yes's");
}
});
}
}
function blah(data, voucher, dates) {
var dfd = $.Deferred();
var voucher_yes_no = new Array();
var voucher_reduction = new Array();
var cycles = 0;
var dates_length = 0;
for(var prop in dates) {
++dates_length;
}
$.each(dates, function(room_id, these_dates) {
$.post('/multiroom/check_voucher/'+voucher+'/'+room_id, function(result) {
if(result.result == 'ok') {
voucher_reduction.push(result.voucher_reduction);
voucher_yes_no.push('yes');
} else {
voucher_yes_no.push('no');
}
++cycles;
if(cycles == dates_length) {
data.push(voucher_yes_no);
data.push(voucher_reduction);
dfd.resolve();
}
}, 'json');
});
return dfd.promise();
}
Can you show how voucher_reduction is defined?
I am wondering where the second line of the debug output comes from, the one starting with '0'.
in this line:
console.log(vouncher_reduction[prop]);
^
The name of the variable is wrong (then) and probably that is breaking your code.
I think there are no problem with your loop.
But perhaps with your object.
Are you sure what properties has enumerable ?
Try to execute this to check :
Object.getOwnPropertyDescriptor(voucher_reduction,'0');
If it return undefined, the property was not exist.

How does jQuery do async:false in its $.ajax method?

I have a similar question here, but I thought I'd ask it a different way to cast a wider net. I haven't come across a workable solution yet (that I know of).
I'd like for XCode to issue a JavaScript command and get a return value back from an executeSql callback.
From the research that I've been reading, I can't issue a synchronous executeSql command. The closest I came was trying to Spin Lock until I got the callback. But that hasn't worked yet either. Maybe my spinning isn't giving the callback chance to come back (See code below).
Q: How can jQuery have an async=false argument when it comes to Ajax? Is there something different about XHR than there is about the executeSql command?
Here is my proof-of-concept so far: (Please don't laugh)
// First define any dom elements that are referenced more than once.
var dom = {};
dom.TestID = $('#TestID'); // <input id="TestID">
dom.msg = $('#msg'); // <div id="msg"></div>
window.dbo = openDatabase('POC','1.0','Proof-Of-Concept', 1024*1024); // 1MB
!function($, window, undefined) {
var Variables = {}; // Variables that are to be passed from one function to another.
Variables.Ready = new $.Deferred();
Variables.DropTableDeferred = new $.Deferred();
Variables.CreateTableDeferred = new $.Deferred();
window.dbo.transaction(function(myTrans) {
myTrans.executeSql(
'drop table Test;',
[],
Variables.DropTableDeferred.resolve()
// ,WebSqlError
);
});
$.when(Variables.DropTableDeferred).done(function() {
window.dbo.transaction(function(myTrans) {
myTrans.executeSql(
'CREATE TABLE IF NOT EXISTS Test'
+ '(TestID Integer NOT NULL PRIMARY KEY'
+ ',TestSort Int'
+ ');',
[],
Variables.CreateTableDeferred.resolve(),
WebSqlError
);
});
});
$.when(Variables.CreateTableDeferred).done(function() {
for (var i=0;i < 10;i++) {
myFunction(i);
};
Variables.Ready.resolve();
function myFunction(i) {
window.dbo.transaction(function(myTrans) {
myTrans.executeSql(
'INSERT INTO Test(TestID,TestSort) VALUES(?,?)',
[
i
,i+100000
]
,function() {}
,WebSqlError
)
});
};
});
$.when(Variables.Ready).done(function() {
$('#Save').removeAttr('disabled');
});
}(jQuery, window);
!function($, window, undefined) {
var Variables = {};
$(document).on('click','#Save',function() {
var local = {};
local.result = barcode.Scan(dom.TestID.val());
console.log(local.result);
});
var mySuccess = function(transaction, argument) {
var local = {};
for (local.i=0; local.i < argument.rows.length; local.i++) {
local.qry = argument.rows.item(local.i);
Variables.result = local.qry.TestSort;
}
Variables.Return = true;
};
var myError = function(transaction, argument) {
dom.msg.text(argument.message);
Variables.result = '';
Variables.Return = true;
}
var barcode = {};
barcode.Scan = function(argument) {
var local = {};
Variables.result = '';
Variables.Return = false;
window.dbo.transaction(function(myTrans) {
myTrans.executeSql(
'SELECT * FROM Test WHERE TestID=?'
,[argument]
,mySuccess
,myError
)
});
for (local.I = 0;local.I < 3; local.I++) { // Try a bunch of times.
if (Variables.Return) break; // Gets set in mySuccess and myError
SpinLock(250);
}
return Variables.result;
}
var SpinLock = function(milliseconds) {
var local = {};
local.StartTime = Date.now();
do {
} while (Date.now() < local.StartTime + milliseconds);
}
function WebSqlError(tx,result) {
if (dom.msg.text()) {
dom.msg.append('<br>');
}
dom.msg.append(result.message);
}
}(jQuery, window);
Is there something different about XHR than there is about the executeSql command?
Kind of.
How can jQuery have an async=false argument when it comes to Ajax?
Ajax, or rather XMLHttpRequest, isn't strictly limited to being asynchronous -- though, as the original acronym suggested, it is preferred.
jQuery.ajax()'s async option is tied to the boolean async argument of xhr.open():
void open(
DOMString method,
DOMString url,
optional boolean async, // <---
optional DOMString user,
optional DOMString password
);
The Web SQL Database spec does also define a Synchronous database API. However, it's only available to implementations of the WorkerUtils interface, defined primarily for Web Workers:
window.dbo = openDatabaseSync('POC','1.0','Proof-Of-Concept', 1024*1024);
var results;
window.dbo.transaction(function (trans) {
results = trans.executeSql('...');
});
If the environment running the script hasn't implemented this interface, then you're stuck with the asynchronous API and returning the result will not be feasible. You can't force blocking/waiting of asynchronous tasks for the reason you suspected:
Maybe my spinning isn't giving the callback chance to come back (See code below).

Categories