Ok, I'm a bit of a n00b when it comes to JS (I'm not the greatest programmer) so please be gentle - specially if my questions been asked already somewhere and I'm too stupid to find the right answer. Self deprecation out of the way, let's get to the question.
Problem
There is a site me and a large group of friends frequently use which doesn't display all the information we may like to know - in this case an airline bookings site and the class of travel.
While the information is buried in the code of the page, it isn't displayed anywhere to the user.
Using a Greasemonkey script, I'd like to liberate this piece of information and display it in a suitable format.
Here's the psuedocode of what I'm looking to do.
Search dom for specified element
define variables
Find a string of text
If found
Set result to a variable
Write contents to page at a specific location (before a specified div)
If not found
Do nothing
I think I've achieved most of it so far, except for the key bits of:
Searching for the string: The page needs to search for the following piece of text in the page HEAD:
mileageRequest += "&CLASSES=S,S-S,S-S";
The Content I need to extract and store is between the second equals (=) sign and the last comma ("). The contents of this area can be any letter between A-Z.
I'm not fussed about splitting it up into an array so I could use the elements individually at this stage.
Writing the result to a location: Taking that found piece of text and writing it to another location.
Code so far
This is what I've come up so far, with bits missing highlighted.
buttons = document.getElementById('buttons');
''Search goes here
var flightClasses = document.createElement("div");
flightClasses.innerHTML = '<div id="flightClasses"> ' +
'<h2>Travel classes</h2>' +
'For the above segments, your flight classes are as follows:' +
'write result here' +
'</div>';
main.parentNode.insertBefore(flightClasses, buttons);
If anyone could help me, or point me in the right direction to finish this off I'd appreciate it.
The Content I need to extract and store is between the second equals (=) sign and the last comma (").
Do you mean "is between the second equals (=) sign and the last quote (")"?
And I assume that this:
mileageRequest += "&CLASSES=S,S-S,S-S";
is in a script tag?
If so then it looks like there will be a JS variable on the page called mileageRequest which you can access from Greasemonkey with unsafeWindow.mileageRequest and assuming that you can access the data you want with something like:
// check that the mileageRequest variable exists
if(unsafeWindow.mileageRequest){
// it exists
var myString = unsafeWindow.mileageRequest.match(/&CLASSES=([^&=]*)/i);
if(myString){
// my string exists
myString = myString[1];
}
else{
// my sting does not exist
}
}
else {
// it does not exist
}
or you can try:
var myString = document.getElementsByTagName('head')[0].innerHTML.match(/mileageRequest\s*\+=\s*"&CLASSES=([^"]*)";/i);
if(myString){
// my string exists
myString = myString[1];
}
else{
// my string does not exist
}
Related
I have a simple script to generate a doc and PDF upon form submission. It worked well on simple template (e.g. Only 1 sentence, First name, Last name and Company name).
However, when I use a template that's longer, having many fields, and formatting, the code runs but replace the text randomly.
I have tried to hardcode the fields of forms in ascending order as the doc template. However it still replace the text randomly
Can anybody points out what have I done wrong?
My code:
function myFunction(e) {
var response = e.response;
var timestamp = response.getTimestamp();
var [companyName, country, totalEmployees,totalPctWomenEmployees,numberNationality,name1,position1,emailAdd1,linkedin1,funFact1,name2,position2,emailAdd2,linkedin2,gameStage,gameStory] = response.getItemResponses().map(function(f) {return f.getResponse()});
var file = DriveApp.getFileById('XXXXX');
var folder = DriveApp.getFolderById('XXXXX')
var copy = file.makeCopy(companyName + '_one pager', folder);
var doc = DocumentApp.openById(copy.getId());
var body = doc.getBody();
body.replaceText('{{Company Name}}', companyName);
body.replaceText('{{Name}}', name1);
body.replaceText('{{Position}}', position1);
body.replaceText('{{Email}}', emailAdd1);
body.replaceText('{{Linkedin}}', linkedin1);
body.replaceText('{{Fun Fact}}', funFact1);
body.replaceText('{{Game Stage}}', gameStage);
body.replaceText('{{Game Story}}', gameStory);
doc.saveAndClose();
folder.createFile(doc.getAs("application/pdf"));}
My template -
Result -
Question - Does that mean the array declaration in line 3 was supposed to match the order of my form responses columns?
You can use Regular Expresion:
body.replace(/{{Company Name}}/g, companyName); // /g replace globaly all value like {{Company Name}}
Finally I found what have went wrong after so many trials and errors!
The reason is because I declared the array variables randomly without following the order of the form responses columns.
The issue is with the part -
var [companyName, country, totalEmployees,totalPctWomenEmployees,numberNationality,name1,position1,emailAdd1,linkedin1,funFact1,name2,position2,emailAdd2,linkedin2,gameStage,gameStory] = response.getItemResponses().map(function(f) {return f.getResponse()});
It's actually pulling responses from the spreadsheet, and should be corrected in order. The wrongly mapped values was what causing the replacement of text went haywire. I corrected the order as per form responses and it is all good now.
Learning points:
If you swapped around the variables, what response.getItemResponses().map(function(f) {return f.getResponse()} does is that it will go through the form responses column by column in order, and it will map the content to the wrong variable. As a result, when you replace your text later using body.replaceText('{{Game Stage}}', gameStage), there might be possibility that whatever stored in gameStage might be name1. Hence the replaced text will be wrong. And you will scratch your head until it bleeds without knowing why.
I saw #Tanaike's comment after I found the answer, but totally spot on!
So I can append text to a textarea using this method
document.getElementById('myArea').value += msg;
This tacks the new input onto the end of the current input.
Suppose the textarea already contains text. Suppose also that using "=" instead of "+=" and inputting the values textarea already had along with the new ones is not a possible solution in this context
How would one input new text to this textarea on the correct line and in the correct position with respect to the text that is already in place?
Here is a YouTube video demonstrating the problem
https://www.youtube.com/watch?v=GpwEuI3_73I&feature=youtu.be
UPDATE:
Instead of sending one letter at a time, I sent the whole textarea each time a key is pressed. Obviously more computationally taxing, but that's the only solution I have right now. I am still interested in hearing any better solutions if you have one!
I'm assuming you send only the last character typed (as in your original approach), and it is stored in a variable named "newChar".
Take this as pseudo-code, although I hope it does not require many changes to actually work:
// deserialize the text of the target textearea
var txt = targetTextarea.text;
var txtAsArray = txt.split(/\r?\n/);
var txtLine = txtAsArray[cursorRowNum];
// write the new character in the right position (but in memory)
txtLine = txtLine.substr(0, cursorColNum) + newChar + txtLine.substr(cursorColNum);
// now serialize the text back and update the target textarea
txtAsArray[cursorRowNum] = txtLine;
txt = txtAsArray.join("\n");
targetTextarea.text = txt;
A reference used was: How in node to split string by newline ('\n')?
Regarding performance, there is no additional network activity here, and we are accessing the DOM only twice (first and last line). Remember than accessing the DOM is around 100 times slower than plain variables in memory as shown by http://www.phpied.com/dom-access-optimization/ .
That "txt = txtAsArray.join("\n");" might need to be "txt = txtAsArray.join("\r\n");" on Windows. Detecting if you are in one or the other is explained at How to find the operating system version using JavaScript as pointed by Angel Joseph Piscola.
Hi this will add text to existing text in textarea
i have try that
var msg = "Hi How are you ?";
document.getElementById('myArea').value += msg;
I'm trying to do something very simple, but I can't get to work the way I intend. I'm sure it's doing exactly what I'm asking it to do, but I'm failing to understand the syntax.
Part 1:
In the following example, I want to extract the part of the string between geotech and Input.
x = "geotechCITYInput"
x.match(/^geotech(.*)(?:Input|List)$/)
The result:
["geotechCITYInput", "CITY"]
I've been writing regex for many years in perl/python and even javascript, but I've never seen the ?: syntax, which, I think, is what I'm supposed to use here.
Part 2:
The higher level problem I'm trying to solve is more complicated. I have a form with many elements defined as either geotechXXXXInput or geotechXXXXList. I want to create an array of XXXX values, but only if the name ends with Input.
Example form definition:
obj0.name = "geotechCITYInput"
obj1.name = "geotechCITYList"
obj2.name = "geotechSTATEInput"
obj3.name = "geotechSTATEList"
I ultimately want an array like this:
["CITY","STATE"]
I can iterate over the form objects easily with an API call, but I can't figure out how to write the regex to match the ones I want. This is what I have right now, but it doesn't work.
geotechForm.forEachItem(function(name) {
if(name.match(/Input$/)
inputFieldNames.push( name.match(/^geotech(.*)Input$/) );
});
Any suggestions would be greatly appreciated.
You were missing the Input and List suffix in your regex. This will match if the name starts with geotech and ends with either Input or List and it will return an array with the text in the middle as the second item in the array.
geotechForm.forEachItem(function (name) {
var match = name.match(/^geotech(.*)(Input|List)$/);
if (match) {
inputFieldNames.push(match[1]);
}
});
I want to find and replace text in a HTML document between, say inside the <title> tags. For example,
var str = "<html><head><title>Just a title</title></head><body>Do nothing</body></html>";
var newTitle = "Updated title information";
I tried using parseXML() in jQuery (example below), but it is not working:
var doc= $($.parseXML(str));
doc.find('title').text(newTitle);
str=doc.text();
Is there a different way to find and replace text inside HTML tags? Regex or may be using replaceWith() or something similar?
I did something similar in a question earlier today using regexes:
str = str.replace(/<title>[\s\S]*?<\/title>/, '<title>' + newTitle + '<\/title>');
That should find and replace it. [\s\S]*? means [any character including space and line breaks]any number of times, and the ? makes the asterisk "not greedy," so it will stop (more quickly) when it finds </title>.
You can also do something like this:
var doc = $($.parseXML(str));
doc.find('title').text(newTitle);
// get your new data back to a string
str = (new XMLSerializer()).serializeToString(doc[0]);
Here is a fiddle: http://jsfiddle.net/Z89dL/1/
This would be a wonderful time to use Javascript's stristr(haystack, needle, bool) method. First, you need to get the head of the document using $('head'), then get the contents using .innerHTML.
For the sake of the answer, let's store $('head').innerHTML in a var called head. First, let's get everything before the title with stristr(head, '<title>', true), and what's after the title with stristr(head, '</title>') and store them in vars called before and after, respectively. Now, the final line is simple:
head.innerHTML = before + "<title>" + newTitle + after;
I have a table with 3 columns (contact person, sector, phone#) each sector cell would contain a lot of data numbers in range like these: (exact format without quote)
"1003, 1005-29/36/38/49, 4587-99, 3301/21, 50123, 9900-04/10-14/20/30/41-44"
Is there a way to add a filter (textbox) to the webpage for a quick look-up?
Example, if I type "9912" --> it will find the string: "9900-04/10-14/20/30/41-44" and highlight it.
note: I have no control over the table (there is no id/class for that column or entire table), searching the entire webpage will be ok, there is no duplicate info elsewhere.
Can someone point me to a good direction? jQuery?
jQuery will help you with the interaction for the textbox, but for processing the strings and extracting the data (i.e. which integers they match) you will need some heavy processing (using regular expressions, String.indexOf() and some loops). It's probably best to do all this processing on page load and cache the results somewhere, but depending on how many strings there are to process, this could lock up the user interface for a while, but assuming this isn't a problem then code a bit like this would do the job of highlighting the correct results
var dataCache = {};
$(selector to collect all your strings).each(function() {
var string = $(this).html();
var matches = yourParserWhichreturnsAnArrayOfIntegers(string);
for(var i = 0, il = matches.length;i<il;i++) {
if(dataCache[matches[i]]) {
dataCache[matches[i]].push(this);
} else {
dataCache[matches[i]] = [this];
}
}
});
$(yourtextbox).change(function() {
$(selector to collect all your strings).removeClass("highlighted");
var matches = dataCache[$(this).val()];
if (matches) {
for(var i=0,il=matches.length;i<il;i++){
$(matches[i]).addClass("highlighted");
}
}
});
If the table appears in the same location within the DOM everytime then you can still get at the data. If this is the case I think you will have to search in the expanded numbers. A regular expression for searching the compressed number format will probably be very complicated. Don't forget to keep a reference to the original data on the page so you can highlight it if a match is found.