i am having a peculiar issue with Chrome at the moment... here's what i'm trying to accomplish:
i have a series of table sections, which have been identified with their IDs accordingly, like this:
T = Tab
G = Group within Tab
S = Sub-Group within Group
# = Numerical index
for example:
<tr id="T1"> = Tab 1
<td id="T1G3"> = Tab 1 , Group 3
<td id="T1G3S1"> = Tab 1, Group 3, Sub-Group 1
Pretty straight forward so far... with the help of JavaScript, i also aim to enable or disabled these groups on the form. Now, here's the problem i'm having... when my form loads the first time, i want to disable everything on the form that requires it. To do so, i created a dynamic function, that could do that for me, where i would specify which tags are affected, and what to look for within the IDs of those tags, and if a match occurs, disable it, like this:
Pseudo and Definition:
Function DisableAll(string TagNamesCSArray, string RegExpContent)
{
Split the tag names provided into an array
- loop through the array and get all tags using document.getElementsByTagName() within page
-- if tags are found
--- loop through collection of tags/elements found
---- if the ID of the element is present, and MATCHES the RegExp in any way
----- disable that item
---- end if
--- end loop
-- end if
- end loop
}
this was fairly easy to implement, and this is the final result:
function DisableAll(TagNames, RegExpStr)
{
//declare local vars
var tagarr = TagNames.split(",");
var collection1;
var IdReg = new RegExp(RegExpStr);
var i;
//loop through getting all the tags
for (i = 0; i < tagarr.length; i++)
{
collection1 = document.getElementsByTagName(tagarr[i].toString())
//loop through the collection of items found, if found
if (collection1)
{
for (y = 0; y < collection1.length; y++)
{
if (collection1[y].getAttribute("id") != null)
{
if (collection1[y].getAttribute("id").toString().search(IdReg) != -1)
{
collection1[y].disabled = true;
}
}
}
}
}
return;
}
And then i place a call to it like this:
DisableAll("tr,td", "^T|^T[0-9]S");
seems simple yes? "Hannnn!" wrong answer batman... this works PERFECTLY, in all browsers, except for Chrome... now why is that? i don't understand. Maybe there's something wrong with my RegExp?
Any help would be greatly appreciated.
Cheers!
MaxOvrdrv
In my case the regex match all possibilities. But the line collection1[y].disabled = true; has no effect because disabled is not a property of a DOM Node.
BTW: The second part of your regex is unnecessary because "^T" will match every ID which begins with T following by a number.
Related
I have a Google Sheet with .gs script that is successfully generating dynamicnewRichTextValue() parameters which are meant to be injected into a Sheet cell that will contain multiple lines of text each with their own URL. I do not know all of the parameters in advance (might be one text and one link, or two each, or more) which is why I am dynamically generating the parameters.
Let's say the end-state should be this (in this case there are only two line items, but there could be more or less:
var RichTextValue=SpreadsheetApp.newRichTextValue()
.setText("mailto:fred#abcdef.com,mailto:jim#abcdef.com")
.setLinkUrl(0,6,"mailto:fred#abcdef.com")
.setLinkUrl(7,19,"mailto:jim#abcdef.com")
.build();
In my script I don't know how many "setText" parameters or "setLinkUrl" statements I will need to generate, so I am doing it dynamically.
This is simple to handle for "setText" because I can just pass a single variable constructed during an earlier loop that builds the "setText" parameters. Let's call that variable setTextContent, and it works like this:
var RichTextValue=SpreadsheetApp.newRichTextValue()
.setText(setTextContent)
So up to this point, everything is great. The problem is that I have another variable that generates the URL portion of the newrichtextvalue() parameters up to the ".build();" statement. So let's call that variable setUrlContent and it is built in an earlier loop and contains the string for the rest of the statement:
.setLinkURL(0,22,"mailto:fred#abcdef.com").setLinkURL(23,44,"mailto:jim#abcdef.com")
I am stumped trying to figure out how to attach it to the earlier bit. I feel like this is something simple I am forgetting. But I can't find it after much research. How do I hook up setUrlContent to the code above so that the command executes? I want to attach the bits above and get back to assigning it all to a variable I can put into a cell:
var emailCell=SpreadsheetApp.newRichTextValue()
.setText("mailto:fred#abcdef.com,mailto:jim#abcdef.com") // I can dynamically create up to here
.setLinkUrl(0,6,"mailto:fred#abcdef.com") // ...but these last couple lines are
.setLinkUrl(7,19,"mailto:jim#abcdef.com") // stuck in a string variable.
.build();
sheet.getRange(1,1,1,1).setRichTextValue(emailCell)
Thanks!
I believe your goal and situation as follows.
You want to use your script by dynamically changing the number of emails.
Modification points:
When your following script is run, I think that the links are reflected to mailto and fred#abcdef..
var emailCell=SpreadsheetApp.newRichTextValue()
.setText("mailto:fred#abcdef.com,mailto:jim#abcdef.com")
.setLinkUrl(0,6,"mailto:fred#abcdef.com")
.setLinkUrl(7,19,"mailto:jim#abcdef.com")
.build();
sheet.getRange(1,1,1,1).setRichTextValue(emailCell)
I thought that you might have wanted the linked email addresses like below.
fred#abcdef.com has the link of mailto:fred#abcdef.com.
jim#abcdef.com has the link of mailto:jim#abcdef.com.
In this answer, I would like to propose the modified script for above direction.
Modified script:
var inputText = "mailto:fred#abcdef.com,mailto:jim#abcdef.com"; // This is your sample text value.
var ar = inputText.split(",").map(e => {
var v = e.trim();
return [v.split(":")[1], v];
});
var text = ar.map(([e]) => e).join(",");
var emailCell = SpreadsheetApp.newRichTextValue().setText(text);
var start = 0;
ar.forEach(([t, u], i) => {
var len = t.length;
emailCell.setLinkUrl(start, start + len, u);
start += len + 1;
});
SpreadsheetApp.getActiveSheet().getRange(1,1,1,1).setRichTextValue(emailCell.build());
In this modification, inputText is splitted to the hyperlink and the text (for example, when your sample value is used, it's fred#abcdef.com and mailto:fred#abcdef.com.), and the text including the hyperlink are put to the cell.
In this case, for example, even when var inputText = "mailto:fred#abcdef.com,mailto:jim#abcdef.com" is modified to var inputText = "mailto:fred#abcdef.com" and var inputText = "mailto:fred#abcdef.com,mailto:jim#abcdef.com,mailto:sample#abcdef.com", each hyperlink are reflected to each text.
Note:
When you want to the hyperlink of mailto:fred#abcdef.com to the text of mailto:fred#abcdef.com, you can also use the following modified script.
var inputText = "mailto:fred#abcdef.com,mailto:jim#abcdef.com"; // This is your sample text value.
var ar = inputText.split(",").map(e => e.trim());
var emailCell = SpreadsheetApp.newRichTextValue().setText(inputText);
var start = 0;
ar.forEach((t, i) => {
var len = t.length;
emailCell.setLinkUrl(start, start + len, t);
start += len + 1;
});
SpreadsheetApp.getActiveSheet().getRange(1,1,1,1).setRichTextValue(emailCell.build());
References:
newRichTextValue()
Class RichTextValueBuilder
Class RichTextValue
I'm using Google Forms to feed a Google Doc (via Google Sheets), and in this Google Doc I have a pre-existing bulleted list. I would like to enter code that will add another bullet to the list.
My approach has been to add a ###newLine### tag to the end of the last pre-filled bullet in the form. I then used replace.Text(###newLine###) in GAS, and then added '\n' for a new line.
The problem is that this '\n' inserts a soft line break (like a Shift+Enter), and it doesn't create a new bullet. It just creates a new line under the prior bullet. I have tested within the doc by adding/removing the bullet associated with the above paragraph, and it is clear that this new line is associated with the above paragraph. What I would like is a a hard line break (like simply pressing Enter) which will create a new bullet.
Here's what the code looks like:
body.replaceText('###newLine###', '\n' + 'Produces a soft (shift+enter) line break.');
Also tried:
body.appendParagraph().
This attached to the end of the body and didn't seem to replaceText.
var insertPar = body.insertParagraph(21, 'test insert paragraph');
body.replaceText('###newBullet###', insertPar);
This would put it in the right spot but not as part of the list.
var listItemTest = body.appendListItem('#listItemTest#');
body.replaceText('###newBullet###', listItemTest);
This appended a numbered list to the end of the body but would not replace text or add to the existing bulleted list.
08-03-19, I tried the following, per Jescanellas's assistance. It works perfectly in the original test doc I provided, but I can't port it over to other docs. I think that's because I'm somehow failing to get the right data to attach it to the list at the right level, but I'm not sure where I'm messing up.
var formDataEntered = functionName.values[11] || ''; //This var is retrieved from the sheet attached to a form. It's the submitted data.
var listItem = body.getListItems(); //We're getting the list.
for (var i = 0; i < listItem.length;i++){ //We're creating a loop here.
var item = body.getListItems()[i]; //This gets the list and applies the loop to it.
if ((item.findText('###bulletTestPlaceholder###')) && (formDataEntered != '')){ //The ###bulletTestPlaceholder### is just a placeholder in the doc where I want to insert the bullet. Your purpose with the item.findText is to identify the list level we're going for - NOT to use the text itself as a placeholder and replace the text.
var index = body.getChildIndex(item); //You're getting all the data about var item (where we got the list and applied the loop).
var level = item.getNestingLevel(); //This gets the nesting level of var item. I'm wondering if this might be the issue as it's not specific to the findText('###bulletTestPlaceholder###')?
var glyph = item.getGlyphType(); //This gets the bullet type.
body.insertListItem((index + 1), formDataEntered).setNestingLevel(level).setGlyphType(glyph); //This is the location in the list where teh bullet will be placed. It also sets the nesting level and glyph type. I've tried playing with the nesting level using integers, but that doesn't fix it.
item.replaceText('###bulletTestPlaceholder###',''); //removes '###bulletTestPlaceholder###' text after it's no longer needed.
break; //stops the loop from looping multiple times.
} else if ((item.findText('###bulletTestPlaceholder###')) && (formDataEntered == '')) {
item.replaceText('###bulletTestPlaceholder###',''); //removes '###bulletTestPlaceholder###' text and avoids new line if no formDataEntered
}
}
After some investigating, and thanks to your examples and links I think I got the solution of this. If there is any issue or I misunderstood something, please tell me and I will correct the post.
This searches for the word ###origApproach### in all the paragraphs (list items) and adds the ###formData### next to it. After this it removes the ###origApproach### paragraph. I commented some lines in case you don't want to remove it.
function myFunction() {
var body = DocumentApp.getActiveDocument().getBody();
var listItem = body.getListItems();
for (var i = 0; i < listItem.length;i++){
var item = body.getListItems()[i];
if (item.findText('###origApproach###')){
var index = body.getChildIndex(item);
var level = item.getNestingLevel();
var glyph = item.getGlyphType();
//In case the indentation is changed:
var indentFirst = item.getIndentFirstLine();
var indentStart = item.getIndentStart();
//Added both setIndents to fix the indentation issue.
body.insertListItem((index + 1), '###formData###').setNestingLevel(level).setGlyphType(glyph).setIndentFirstLine(indentFirst).setIndentStart(indent);
body.removeChild(item); //Comment this if you don't want to remove the ###origApproach### paragraph
//Uncomment this if you want to keep the paragraph and remove ###origApproach###
//item.replaceText('###origApproach###','');
break;
}
}
}
If you remove the paragraph with the word ###origApproach### change index + 1 to index
EDIT
If it's changing your glpyh style, you can force it by using the parameters BULLET, HOLLOW_BULLET, NUMBER, etc instead of the variable glyph.
You can read more about these functions here
I am currently building a Chrome extension which has to find specific pages in a website specifically the Log In / Sign In page, the Sign Up / Register page, the About page and the Contact Us page.
I am trying to achieve this by first getting the list of elements in the page (which I have already done). Now I need to check the innerHTML of the element such that it is a leaf node in the DOM and contains a part of the keyword, and I am trying to do this with a regex. I managed to build a regex which successfully returns what's in between a start or end tag of an element (i.e. the tag name along with its attributes), but not the innerHTML. Below is what I have done so far (with the example for the About page:
var list = document.body.getElementsByTagName("*");
var aboutElement = /^[^<.+>].*About.*[^(<.+>]$/i;
for (var i = 0; i <= list.length; i++) {
if ((aboutElement.test(list[i].innerHTML)) || (aboutElement.test(list[i].alt))) {
list[i].click();
}
}
Any idea what I should add to it such that it only matches leaf nodes (nodes which do not contain other nodes) and not what's in a start or end tag? I also think that with what I've done it's going to match everything in the innerHTML because of the .* part so I may need to change that as well. Any help would be greatly appreciated!
Thanks to two of the answers in the comments I managed to solve the problem. I used .textContent and changed the regex as shown below and it worked.
var list = document.body.getElementsByTagName("*");
var aboutElement = /^(.*?\s*(\bAbout\b)[^$]*)$/i;
for (var i = 0; i <= list.length; i++) {
if ((aboutElement.test(list[i].textContent)) || (aboutElement.test(list[i].alt))) {
list[i].click();
}
}
I'm trying to find certain words in a Google Document, in order to format them via script. The problem is, it seems like findText() is only able to find the word, when it's in the first paragraph. If it's somewhere else, findText() will go nuts and give me (seemingly) random locations for the word. Here is how it's coded:
function findBoldMarks(){
var doc = DocumentApp.openById('docId');
var docText = doc.editAsText();
// search initial bold markup
var srcB0 = body.findText('bold0');
var idB0 = srcB0.getStartOffset();
// search final bold markup
var srcB1 = body.findText('bold1');
var idB1End = srcB1.getEndOffsetInclusive();
// set markup and text wrapped within bold markup as bold
docText.setBold(idB0, idB1End, true);
}
I feel like I must be ignoring something basic here, but after hours struggling with it, I'm not sure anymore. I appreciate any thoughts. Thanks!
To continue searching past the first occurrence, you'll need to wrap the search in loop and provide the second "from" argument in findText().
Here's the start of an example that only searches for 1 word...
function findBoldMarks(){
var body = DocumentApp.getActiveDocument().getBody();
var pattern = "bold0";
var searchResult = body.findText(pattern);
var style = {};
style[DocumentApp.Attribute.BOLD] = true;
while (searchResult !== null) {
var thisElement = searchResult.getElement();
var thisElementText = thisElement.asText();
thisElementText.setAttributes(searchResult.getStartOffset(), searchResult.getEndOffsetInclusive(),style);
// search for next match
searchResult = body.findText(pattern, searchResult);
}
}
...derived from some answers in this post.
Maybe some one can modify to include the text between the two search terms. It doesn't appear that findText() accepts a regular expression search pattern, so another approach may be needed to do that.
In JS, I'm having trouble working out how to split a string coming from an AJAX call.
This is what I have so far:
xmlhttp.onreadystatechange = function()
{
if (xmlhttp.readyState==4 && xmlhttp.status==200)
{
feedUpdateResponse = xmlhttp.responseText;
/////...split script.../////
}
}
xmlhttp.open("GET","https://myDomain.com/myScript.aspx",true);
xmlhttp.send();
Where you have /////...split script...///// in my script above, I need to add a little function that splits the string returned from my AJAX call.
The string simply contains names of DIVs, like this:
feedUpdateResponse = "div1/div2/div3/div4"
I would like to first split the string by its slashes (/) and run a loop through the different values and do stuff to those elements on my page.
To give an idea of what I need to achieve, I have given this example which is a mix of ASP & JS - it's the only way I can possibly describe it (and show that I've had an attempt) :)
MyArray = Split(feedUpdateResponse,"/")
For Each X In MyArray
documentGetElementById('updateAvailable_'+x).style.visibility="visible";
Next
On my page I have an ASP script that produces jquery carousels, all contained by separate DIVs. The DIVs are named DIV1, DIV2 etc. Inside DIV1, for example, is a text element called updateAvailable_div1 which will alert the user "There are new photos available for this feed, please click the refresh button".
Could somebody please explain to me how I can change my example above to work in JS? Just need to split the string into an array and loop through the split values...
You can use .split() to split a string on a specified character with the results returned as an array. So then it's just a matter of looping through the array:
// given your existing variable
// feedUpdateResponse = "div1/div2/div3/div4" as set in the
// code in the question, add this:
var a = feedUpdateResponse.split("/"),
i;
for (i = 0; i < a.length; i++) {
document.getElementById("updateAvailable_" + a[i]).style.visibility
= "visible";
}
Get your array via string.split("/"). Iterate your array using your method of choice. I prefer Array.forEach():
feedUpdateResponse.split("/").forEach(function (item) {
document.getElementById(item).style.visibility = "visible";
});
See the compatibility notes for using .forEach() in older browsers.
As an alternative:
for(element of feedUpdateResponse.split("/")){
do_your_thing();
}
Using for..in will end up giving you the indices on the array (keys), while for..on will give you the elements of the array (values).
You can also do:
for ([index, element] of Object.entries(feedUpdateResponse.split("/"))) {
do_your_thing();
}
In the event that you need the index.
The disadvantage is it not being compatible with IE, but for personal projects or a quick automation script it usually does me plenty fine.
Try this code:
var a = feedUpdateResponse.split("/");
for (i in a) {
document.getElementById("updateAvailable_" + a[i]).style.visibility
= "visible";
}
var feedUpdateResponse = "div1/div2/div3/div4";
var feedUpdateSplit = feedUpdateResponse.split("/");
for (var x = 0; x < feedUpdateSplit.length; x++) {
document.getElementById("updateAvailable_" + feedUpdateSplit[x]).style.visibility = "visible";
}