I hope you're all doing well. So I've been working with PDF.js by Mozilla for a while now. We're using it to display PDF forms to be filled out on a mobile app. Everything works great, I'm just trying to implement a feature where you can cache the users entries so that they can resume from where they left off. For a few reasons I can't just download the PDF to save it and then load it back up when they wat to resume.
Essentially I want to store all the user entries and the Field ID for each of them, which I've already gotten working, and then when the user wants to resume I want it to load the empty PDF, and then automatically re-populate all the fields with the cached entries.
I know I could set the individual text fields, but when I do that it doesn't apply to the annotationStorage so when I parse the form, those fields are read as blank.
I've tried the following lines of code in an attempt to set a field value with the id "5R"
PDFViewerApplication.pdfDocument.annotationStorage.setValue('5R', "Shirboogle");
PDFViewerApplication.pdfDocument.annotationStorage.getAll()['5R'].value = "Shirboogle";
var objs = await PDFViewerApplication.pdfDocument.getFieldObjects();
objs['Address 1 Text Box'][0].value = "Shirboogle";
// and
objs['Address 1 Text Box'][0].defaultValue = "Shirboogle";
// This will actually set the value of the text field, but when I look for it in annotationStorage OR
// getFieldObjects() the value is still unchanged.
document.getElementById('pdfjs_internal_id_5R').value = 'Shapoopsies';
along with many other attempts. I've looked all over and nothing seems to be available, so if you have any ideas please let me know!
In case anyone is having trouble with this, here is the solution I came up with. It seems to work great for my use case but may not be sufficient for every case. I figured I'd at least share what I got to work.
It basically sets everything manually. There are still some UI elements I need to make an if statement for to set, but anyways. Here's my code. Good luck :)
function getFieldValue(id) {
return PDFViewerApplication.pdfDocument.annotationStorage.getAll()[id].value;
}
async function getFieldObjById(id) {
var objs = await PDFViewerApplication.pdfDocument.getFieldObjects();
for(var i=0; i<Object.values(objs).length; i++) {
if(Object.values(objs)[i][0].id == id) {
return Object.values(objs)[i][0];
}
}
}
async function setFieldValue(id, val) {
var fElementId = "pdfjs_internal_id_" + id;
var fObject = await getFieldObjById(id);
var objType = fObject.type;
// Depending on the element type we set the value accordingly.
if(objType == 'text') {
document.getElementById(fElementId).value = val;
PDFViewerApplication.pdfDocument.annotationStorage.setValue(id, {value: val});
}
else if(objType == 'checkbox') {
document.getElementById(fElementId).checked = val;
PDFViewerApplication.pdfDocument.annotationStorage.setValue(id, {value: val});
}
else if(objType == 'combobox') {
document.getElementById(fElementId).selectedIndex = val;
var sLabel = document.getElementById(fElementId).options[document.getElementById(fElementId).selectedIndex].label;
PDFViewerApplication.pdfDocument.annotationStorage.setValue(id, {value: sLabel});
}
}
Related
Hi I am currently using java to hide certain tabs and fields on my forms depending on the population of dropdowns, for example here is a code that is working:
//Display Transfer tab if it is a transfer application
var ctrlApplicationType = Runner.getControl(pageid, 'ApplicationType');
ctrlApplicationType.on('change', function(e)
{
if (this.getValue() == 2)
{
var tabs = pageObj.getTabs(); tabs.show(2);
}
else
{
var tabs = pageObj.getTabs(); tabs.hide(2);
}
}
);
In the example above the dropdown is fed from a lookup table and returns the primary key INT, hence ==2 works fine.
However I now have a problem when I am trying to get this to work with a checkbox, because the problem is a checkbox can have multiple options.
My lookup table for checkbox has 5 options, so if i ticked option 1, 2 and 3, the field (string) is stored as 1,2,3.
What I need to do is to do change the above code so it returns true if it contains 1, ie
if (1,2,3) contains 1 then true
if (2,3) contains 1 then false.
Any ideas would be much appreciated
Okay, against my better judgement (I'd really like to see you make your own attempt based on the information I've already given you), here you go...
var selectedString = "1,2,3"; // from your code, this is this.getValue()
var selectedArray = selectedString.split(","); // split the string into an array using a comma (,) as the split point
var foundInArray = selectedArray.includes('1'); // foundInArray is now a boolean indicating whether or not the value '1' is one of the values in the array.
if(foundInArray)
{
// do the found action
}
else
{
// do the not found action
}
If you want to compare against integer values instead of string values, that's easy enough too.
var integerArray = selectedArray.map(function(x){ return parseInt(x); });
var foundInArray = integerArray.includes(1);
Finally, all of this can be chained into a one-liner:
if(selectedString.split(",").map(function(x){return parseInt(x);}).includes(1))
{
// do found action
}
else
{
// do not found action
}
To iterate through a fixed list and show/hide each, you can do this...
var possibleTabs = [1,2,3,4,5];
for(n in possibleTabs)
{
if(selectedString.split(",").map(function(x){return parseInt(x);}).includes(n))
{
var tabs = pageObj.getTabs(); tabs.show(n);
}
else
{
var tabs = pageObj.getTabs(); tabs.hide(n);
}
}
This, of course, assumes that there is a relation between the checkbox value and the tabs. If there's not, then you're going to have to list them all out as individual if/elseif/else statements, and that is going to get out of hand really quickly.
I'm trying to make hangman in javascript and I want to check if the user has used a letter already. I made a var letterGuessValue = to 0 and if they add an input it = 1. I know this would say know to everything if i got it to work (it doesn't even do anything) but am I on the right track maybe? Here's my code. http://jsbin.com/aWOnAfe/5/edit
I would say add an input to a list and whenever they add another input (aka letter), check this list to see if it is already in there. If it is, then its because they've already used that letter before. If not, then it is a new letter.
I don't see where the difficult part is.
http://jsfiddle.net/DerekL/jgqQ9/
Sample code
var used = {};
$("input").keyup(function(){
var val = this.value;
alert( used[val] ? "Used" : "Not used" );
this.value = "";
used[val] = true;
});
How it works
Assign true to used.LETTER when a letter is entered. Before assigning it though, if it was undefined then it hasn't been used. If it is true then it is used.
Sometimes developers tend to use an Array to record pressed keystrokes when doing key combinations, but in this case, iterating an Array would require both more memory and computation power. A simple object is an enough fit.
Use an array to store all of the used letters and function like this to add new ones.
var inputs = []
function addLetter(letter){
var used = false;
for(var i = 0; i < inputs.length; i++){
if(inputs[i] == letter){
used = true;
break;
}
}
if(!used){
inputs.push(letter);
}
}
The easiest way is to append each letter to a string, like this:
var letters = '';
var letterPressed = 'X'; // uppercase it if appropriate for your language
if (letters.indexOf(letterPressed) > -1)
{
// you already pressed it
}
else
{
letters += letterPressed;
}
You can also use an array to store your list of presses, although IMO that's overkill.
I am learning jQuery and am having issues trying to figure out how to select elements in a multidimensional array. I have a select list with database IDs and I want to set a var with the cost field in the database according to the id that selected. I have all the pieces except for translating the selected ID to a cost. Can someone please help me with getting this right please?
var rangeListData = [{"idrange_list":"1","range_cost":"0","target_range_name":"Self Only"},{"idrange_list":"2","range_cost":"1","target_range_name":"1 Space"},{"idrange_list":"3","range_cost":"2","target_range_name":"2 Spaces"},{"idrange_list":"4","range_cost":"3","target_range_name":"3 Spaces"},{"idrange_list":"5","range_cost":"4","target_range_name":"4 Spaces"},{"idrange_list":"6","range_cost":"5","target_range_name":"5 Spaces"}];
$('#slctPowerTarget').change(function () {
var targetID = $('#slctPowerTarget').val();
var cost $.grep(rangeListData, function(e) { return e.idrange_list == targetID }); // this is the line that is wrong
$('#spanTotalEffectsCost').text(cost);
});
If I put targetID in where cost is it lists fine. But when I try to look this up nothing happens. It is not right somehow and I am not sure what else to try. I think I get how idrange_list == targetID is supposed to match them but not sure how to call the related range_cost.
Thanks for any help you can offer! I read through the docs at jquery.com but can't seem to wrap my head around them.
You can do this :-
// Get the Multidimensional Array first
var data = $.grep(rangeListData, function (e) {
return e.idrange_list === targetID
});
// Get the range cost from the array
var cost = data[0].range_cost;
// Check the value in console for debugging purpose
console.log(cost);
Here is the final code. I also added an IF clause in there in case they select the default setting. This way it will reset instead of tossing an error and keeping page calculations working no matter if they change the drop downs or go back to "Select..."
$('#slctPowerRange').change(function () {
var rangeID = $('#slctPowerRange').val();
if (rangeID > 0) {
var rdata = $.grep(rangeListData, function (e) {
return e.idrange_list === rangeID
});
var rcost = rdata[0].range_cost;
}
else {
var rcost = 0 ;
}
$('#hdnRangeCost').val(rcost);
});
My function to implement the search is below. The issue I have is I need to track what rows I have to go through to find the URL. I'm building a navigation "widget" and I need it to expand to the correct place based on the URL. Seeing as the URL could be N rows deep, I need a method to track the rows that it passed through.
E.G: row[1].tree.row[3].tree.row[0] , this way I know to expand the navigation for the second element, then the fourth element, then highlight the first element in that list.
The issue is with the rowNum = rowNum+"x"+x; that I pass back to the function. I think I might be overtired when I thought that would work, I didn't think it through.
Suggestions?
Thanks!
I had another question out there about this same function, but this question is different. Is it bad form to submit an additional question?
function lmIntra_LeftNavBuilder_findURL(url)
{
return lmIntra_LeftNavBuilder_searchJson(jsonLNav.tree[0],url,null);
}//end findURL
function lmIntra_LeftNavBuilder_searchJson(tree,url,rowNum)
{
if(rowNum == null)
{
rowNum="";
}
for(var x=0; x<=tree.rows.length-1;x++)
{
var cururl = "";
if(typeof tree.rows[x] ==="undefined")
{
cururl="";
}else
{
var cururl = tree.rows[x].url;
}
if(url == cururl )
{
//return tree.rows[x].title;
return rowNum + " treeDepth:"+tree.pos;
}//end if
else
{
if(typeof tree.rows[x]!= "undefined")
{
if(typeof tree.rows[x].tree.rows != "undefined")
{
rowNum = rowNum+"x"+x;
var t = lmIntra_LeftNavBuilder_searchJson( tree.rows[x].tree,url,rowNum);
if (t) return t;
}//end if
}//end if typeof tree.rows[x].tree!= "undefined"
}//end else
}//end for
}//end searchJson
Here's a simpler json object. It's fully formed, it just doesn't have the depth. The full one is 38K characters, so I'll leave it out.
var jsonLNav = {itemClassName:"NodeLink",linkClassName:"NodeLinkTitle",linkHideClassName:"HideFromProd",navCategoryClassName:"NavCategory",onLoadJS:"",tree:[{pos:1,wid:"263a97c2-7cb9-470c-bf86-cadc28ae1323",pid:"1",rows:[{hide:0,title:"More IT Help",isNC:0,isMig:0,url:"http://vm-hsspdv-d09p/en-us/Help/Pages/ITHelp.aspx",isOL:0,tree:{pos:2,wid:"263a97c2-7cb9-470c-bf86-cadc28ae1323",pid:"3"}},{hide:0,title:"Office 2010",isNC:0,isMig:1,url:"http://office2010.lmig.com/Pages/Default.aspx",isOL:0,tree:{pos:2,wid:"263a97c2-7cb9-470c-bf86-cadc28ae1323",pid:"9"}},{hide:0,title:"E-mail Management",isNC:0,isMig:0,url:"http://vm-hsspdv-d09p/en-us/Help/EmailManagement/Pages/default.aspx",isOL:0,tree:{pos:2,wid:"8be66348-8da1-4e5c-90c5-0930d2f52d1a",pid:"123"}},]}]};
If you really want to stick with the approach you have, though, I don't think it's really too far off. If I understand what you want, the biggest problem is that you need to do something like:
if(url == cururl )
{
rowNum = rowNum+"x"+x;
return rowNum + " treeDepth:"+tree.pos;
}
Presumably everything that exists in this tree maps to something that exists in the DOM, right? I think the most sensible option would be to stop traversing this object to find what you want, use a library like jQuery with a selector engine to select the node you want, and then use said library to traverse back up the DOM. Even traversing the DOM without a library might be easier for you.
I am not family familiar with prototype but have been tasked to make some changes to a color picker. I have made the majority of the changes without too much issue.
What I need to do though is listen for the forms input.
Can anyone advise on how this is done?
I found this but I don't understand how to implement it: http://api.prototypejs.org/dom/form/element/observer/
This is the element I have been working with in the plugin.
Instance One
//
// picker sample text
//
this.textValue = document.createElement('input');
this.textValue.type = "text";
this.textValue.name = "textValue";
this.textValue.className = options.textValueClass;
this.header.appendChild(this.textValue);
Instance 2
setColor: function(color) {
this.textValue.setAttribute('value', color);
this.sample.style.backgroundColor = color;
},
I want Instance 3 to be something like this.
if (this.textValue.<<changes>> && this.textValue.<<value.length>> == 7) {
// Check if valid hex
// Trigger Save
}
Could someone help fill in the << >> please.
see http://www.prototypejs.org/api/event/observe.
this.observe('change', this.validateOnChange.bind(this));
validateOnChange: function(event) {
var value;
value = $(this.fieldid).getValue();
if (value.length == 7) {
//Check if valid hex
// Trigger Save
}
}