I need to add a signature field on a form, that will be used on an iPad to sign documents.
I need a plugin that will allow multiple signature inputs on the same form.
I found this jQuery plugin "signfield" that works great...
https://github.com/cchantep/jquery.signfield
But it has one huge issue!
On desktop firefox, safari, etc, it works great.
On an iPad, it only allows you to draw one line at a time - if you raise your finger and then try to draw another line, the canvas clears!
That is fine if your signature can be drawn as one continuous line, but that is very unlikely!
On desktop safari it works with no problem - you can draw many lines. But on mobile safari it has this issue.
The issue happens with the demo, so it is an issue with the plugin, not with my implementation of it.
Help!!
For jSignature:
keep in mind I have modified the library a little so that I can print text on the canvas as well so it says what they are agreeing to (I have removed my custome code from the code below to show more of a raw example for the base library)
HTML:
<div id="signature"></div>
JS:
Initialize the signature:
$("#signature").jSignature({ color: "#000000", "decor-color": "#000000", lineWidth: 2);
Check that at least one stroke was performed
if ($("#signature").jSignature('getData', 'native', '', '').length === 0) {
// user has not signed
} else {
// user has signed
}
Get signature image base64 string:
model.getSignatureData = function () {
return $("#signature").jSignature("getData", "image");
}
Set observable for signature base64 value:
model.SignatureValue(model.getSignatureData()[1]);
Then I simply pass the signature value property in the JSON I post to my API
Related
Update:
Please see the answer noted below as, ultimately, the problem had nothing to do with jsquery.
=============
Issue:
I submit an object to jquery to convert into a serialized string that will become part of a "POST" request to a server, and the data returned from the serialization request is different than the data sent on many occasions.
An example:
The JavaScript code that implements the server POST request:
function send_data(gpg_data) {
var query_string;
query_string = '?' + $.param(gpg_data, traditional = true);
console.log('gpg_data =', gpg_data)
console.log('query_string =', query_string);
$.post(server_address + query_string);
return;
}
This is the structure sent to the jquery param() function.
(copied from the browser console in developer mode.)
gpg_data =
{controller_status: 'Connected', motion_state: 'Stopped', angle_dir: 'Stopped', time_stamp: 21442, x_axis: 0, …}
angle_dir: "Stopped"
controller_status: "Connected"
force: 0
head_enable: 0
head_x_axis: 0
head_y_axis: 0
motion_state: "Stopped"
time_stamp: 21490
trigger_1: 0
trigger_2: 0
x_axis: 0
y_axis: "0.00"
. . . and the returned "query string" was:
query_string = ?controller_status=Connected&motion_state=Stopped&angle_dir=Stopped&time_stamp=21282&x_axis=0&y_axis=0.00&head_x_axis=0&head_y_axis=0&force=0&trigger_1=1&trigger_2=1&head_enable=0
The data received by the server is:
ImmutableMultiDict([('controller_status', 'Connected'), ('motion_state', 'Stopped'), ('angle_dir', 'Stopped'), ('time_stamp', '21282'), ('x_axis', '0'), ('y_axis', '0.00'), ('head_x_axis', '0'), ('head_y_axis', '0'), ('force', '0'), ('trigger_1', '1'), ('trigger_2', '1'), ('head_enable', '0')])
For example, note that "trigger_1" returns 1 when the data sent to it is a zero.
I have tried setting the query to "traditional = true" to revert to an earlier style of query handling as some articles suggested - which did not work. I tried this with jquery 3.2 and 3.6.
I am not sure exactly how jquery manages to munge the data so I have no idea where to look.
I have looked at my script and at the unpacked jquery code, and I can make no sense out of why or how it does what it does.
Any help understanding this would be appreciated.
P.S.
web searches on "troubleshooting jquery" returned very complex replies that had more to do with editing e-commerce web pages with fancy buttons and logins than with simply serializing data.
P.P.S.
I am tempted to just chuck the jquery and write my own serialization routine. (grrrr!)
===================
Update:
As requested, a link to the browser-side context.
To run: unpack the zip file in a folder somewhere and attach an analog joystick/gamepad to any USB port, then launch index.html in a local browser. Note that a purely digital gamepad - with buttons only or with a joystick that acts like four buttons - won't work.
You will want to try moving joystick axes 1 and 2, (programmatically axes 0 and 1) and use the first (0th) trigger button.
You will get a zillion CORS errors and it will complain bitterly that it cannot reach the server, but the server side context requires a GoPiGo-3 robot running GoPiGo O/S 3.0.1, so I did not include it.
Note: This does not work in Firefox as Firefox absolutely requires a "secure context" to use the Gamepad API. It does work in the current version of Chrome, (Version 97.0.4692.99 (Official Build) (64-bit)), but throws warnings about requiring a secure context.
Please also note that I have made every attempt I know how to try to troubleshoot the offending JavaScript, but trying to debug code that depends on real-time event handling in a browser is something I have not figured out how to do - despite continuous searching and efforts. Any advice on how to do this would be appreciated!
======================
Update:
Researching debugging JavaScript in Chrome disclosed an interesting tidbit:
Including the line // #ts-check as the first line in the JavaScript code turns on additional "linting" (?) or other checks that, (mostly) were a question of adding "var" to the beginning of variable declarations.
However. . . .
There was one comment it made:
gopigo3_joystick.x_axis = Number.parseFloat((jsdata.axes[0]).toFixed(2));
gopigo3_joystick.y_axis = Number.parseFloat(jsdata.axes[1]).toFixed(2);
I could not assign gopigo3_joystick.y_axis to a string object, (or something like that), and I was scratching my head - that was one of the pesky problems I was trying to solve!
If you look closely at that second line, you will notice I forgot a pair of parenthesis, and that second line should look like this:
gopigo3_joystick.y_axis = Number.parseFloat((jsdata.axes[1]).toFixed(2));
Problem solved - at least with respect to that problem.
I figured it out and it had nothing to do with jquery.
Apparently two things are true:
The state of the gpg_data object's structure is "computed", (snapshot taken), the first time the JavaScript engine sees the structure and that is the state that is saved, (even though the value may change later on). In other words, that value is likely totally bogus.
Note: This may only be true for Chrome. Previous experiments with Firefox showed that these structures were updated each time they were encountered and the values seen in the console were valid. Since Firefox now absolutely requires a secure context to use the gamepad API, I could not use Firefox for debugging.
I was trying to be "too clever". Given the following code snippet:
function is_something_happening(old_time, gopigo3_joystick) {
if (gopigo3_joystick.trigger_1 == 1 || gopigo3_joystick.head_enable == 1) {
if (old_time != Number.parseFloat((gopigo3_joystick.time_stamp).toFixed(0))) {
send_data(gopigo3_joystick)
old_time = gopigo3_joystick.time_stamp
}
}
return;
}
The idea behind this particular construction was to determine if "something interesting" is happening, where "something interesting" is defined as:
A keypress, (handled separately)
A joystick movement if either the primary trigger or the pinky trigger is pressed.
Movement without any trigger pressed is ignored so that if the user accidentally bumps against the joystick, the robot doesn't go running around.
Therefore the joystick data only gets updated if the trigger is pressed. In other words, trigger "release" events - the trigger is now = 0 - are not recorded.
The combination of these two events - Chrome taking a "snapshot" of object variables once and once only, (or not keeping them current) - and the trigger value persisting, lead me to believe that jquery was the problem since the values appeared to be different on each side of the jquery call.
Discovering the Web Audio Api I wanted to draw a waveform for sound files. Now, I am aware of the image dimension limitations in some browsers, and I tried to look them up, but they seem to be ever changing (or at least memory differences like Chrome Desktop vs Chrome Mobile).
I tried to look up how to test if an image, or a Canvas / 2D Context can be of a certain size with almost no success. However, when testing this thing in Firefox I did get an error in the console so I tried the following method:
wfWidth = source.buffer.duration*100;
document.getElementById("waveform").width = wfWidth;
wfCtx = document.getElementById("waveform").getContext("2d");
var success = false;
while(success == false)
{
try {
var temp = wfCtx.getImageData(0,0,10,10); // this produced an error further down the code, so I use this as my test case.
success = true;
} catch(err) {
wfWidth = wfWidth / 2;
document.getElementById("waveform").width = wfWidth;
wfCtx = document.getElementById("waveform").getContext("2d");
}
console.log(success);
}
This does seem to work in Firefox as the console first outputs false showing that the canvas is too big and then true after halving the width of the canvas and the waveform is shown.
However, in Google Chrome on Desktop the canvas seems to be of a certain size (as indicated by a scroll bar) but it is totally blank. When I right-click to save image, it is a 0 byte txt file. On Chrome Mobile (android) I get this little square sad face. Guess that method of checking doesn't work in Chrome.
What would be the best way to test if the canvas is, well, valid, and resize if it is not?
I'm writing a simple Automator script in Javascript.
I want to send a key-code(or key-storke) to an OS X application that is not in front.
Basically, I want to run this code and do my things while the script opens a certain application, write text, and hit enter - all of this without bothering my other work.
I want something like this:
Application("System Events").processes['someApp'].windows[0].textFields[0].keyCode(76);
In Script Dictionary, there is keyCode method under Processes Suite.
The above code, however, throws an error that follows:
execution error: Error on line 16: Error: Named parameters must be passed as an object. (-2700)
I understand that the following code works fine, but it require the application to be running in front:
// KeyCode 76 => "Enter"
Application("System Events").keyCode(76);
UPDATE: I'm trying to search something on iTunes(Apple Music). Is this possible without bringing iTunes app upfront?
It's possible to write text in application that is not in front with the help of the GUI Scripting (accessibility), but :
You need to know what UI elements are in the window of your specific
application, and to know the attributes and properties of the
specific element.
You need to add your script in the System Preferences --> Security
& Privacy --> Accessibility.
Here's a sample script (tested on macOS Sierra) to write some text at the position of the cursor in the front document of the "TextEdit" application.
Application("System Events").processes['TextEdit'].windows[0].scrollAreas[0].textAreas[0].attributes["AXSelectedText"].value = "some text" + "\r" // r is the return KEY
Update
To send some key code to a background application, you can use the CGEventPostToPid() method of the Carbon framework.
Here's the script to search some text in iTunes (Works on my computer, macOS Sierra and iTunes Version 10.6.2).
ObjC.import('Carbon')
iPid = Application("System Events").processes['iTunes'].unixId()
searchField = Application("System Events").processes['iTunes'].windows[0].textFields[0]
searchField.buttons[0].actions['AXPress'].perform()
delay(0.1) // increase it, if no search
searchField.focused = true
delay(0.3) // increase it, if no search
searchField.value = "world" // the searching text
searchField.actions["AXConfirm"].perform()
delay(0.1) // increase it, if no search
// ** carbon methods to send the enter key to a background application ***
enterDown = $.CGEventCreateKeyboardEvent($(), 76, true);
enterUp = $.CGEventCreateKeyboardEvent($(), 76, false);
$.CGEventPostToPid(iPid, enterDown);
delay(0.1)
$.CGEventPostToPid(iPid, enterUp);
I've implemented this UX for ExtJs 4 (it generates an Excel file from an ExtJs 4 grid or store)
http://druckit.wordpress.com/2013/10/26/generate-an-excel-file-from-an-ext-js-4-grid/#comment-982
and it works perfectly in Chrome, however I keep getting this error " the data area passed to a system call is too small" in any version of IE
Here is the fragment of code that seems to be the problem, the full code is in the link above.
var el = Ext.DomHelper.append(gridEl, {
tag: "a",
download: title + "-" + Ext.Date.format(new Date(), 'Y-m-d Hi') + '.xls',
//download: 'descarga.xls',
href: location
});
el.click(); //this line seems to be causing the error
Ext.fly(el).destroy();
}
I know there is downlodify and other options (like server side generating) but they are not an option at this point for me.
Is there any chance I can make this UX work in IE?
Can anyone point me in the right direction ?
Thank you.
Using the listed method will not work well with IE because IE has a limit of 2083 characters. If you debug the code in this fiddle https://fiddle.sencha.com/#fiddle/17j you'll notice that the location variable is well over 5000 characters and also fails in IE. I'm assuming the issue is the same if you debug your code as well.
I have checked online including this web site and have been unable to find a solution to my problem.
I am trying to us the JQuery File Upload plugin and have made some amendments to restrict the files types to CSV and XML, as well as restricting to 1 file only and up to 5MB per file. These new properties work fine and it also works fine in all browsers except IE.
I have bound an event on the fileupload event that will render the CSV as a HTML table. This works fine in all browsers except IE. In IE, it either throws an error or freezes with the green progress bar at the top right displaying the following information:
7.123775601068567 bit/s | 00:00:00 | 100.00 % | 0.00 KB / 0.00 KB
It actually looks like it is hanging as it does not seem to complete the upload. And when I reload the same page it shows the correct display! without the progress bar!
UPDATE: The code is fine when I simply upload the CSV file. Now the problem appears when I attempt to include a callback option. It seems related to the 'fileuploadcompleted' event, which I updated from 'fileuploaddone', which has improved the result but still not right and does not execute and render the HTML table at all (See link above for example)
// Load existing files:
$('#fileupload').each(function () {
var that = this;
$.getJSON(this.action, function (result) {
if (result && result.length) {
$(that).fileupload('option', 'done')
.call(that, null, {result: result});
}
});
}).bind('fileuploadcompleted', function (e, data) {
//console.log('fileuploaddone:start');
var $filename = $('#fileupload td.name').text().trim();
//console.log('filename is ' + $filename);
$.get('../jQuery-File-Upload/server/php/files/' + $filename, function(data) {
$('#CSVSource').html('<pre>' + data + '</pre>');
});
$('#CSVTable').CSVToTable('../jQuery-File-Upload/server/php/files/' + $filename,{
loadingImage: 'img/loading-table.gif',
startLine: 0 }).bind("loadComplete",function() {//for future use});
}).bind('fileuploaddestroy', function (e, data) {
//console.log('fileuploaddestroy');
$('div#CSVTable').fadeOut(1000);
});
Any ideas how to get this working in IE?
Many thanks.
ok the issue is resolved after much digging, though solution was quite simple and has been covered here:
How to deal with ie8 jquery object doesn't support this property or method Error?
So basically in the code above I should have been using the JQuery version of trim, which was updated as follows:
var $filename = $.trim($('#fileupload td.name').text());
posting the question in some strange way helped me resolve this issue :)
As a side note: I've also noticed that if you have htaccess restrictions on the folder where your 'upload' web page is, you can also have different behaviour in IE. For example, with access restrictions set, the upload works though it does not display the actual file uploaded, despite uploading. And when you delete the file, it asks you to log in.