Using documentApp Text class methods in a google sheet - google-apps-script

I have a range with rich text hyperlinks in it in a googlesheet, copied and pasted from elsewhere.
I want to create a function to extract the URLs - there's a method called .getLinkUrl in the text class that I think will do the trick.
However, SpreadsheetApp doesn't have a Text class, so I think I need the .getLinkUrl method from the Text class in DocumentApp.
I'd like to do something like this:
function getURL(range) {
var textElement = DocumentApp.create("temp").getBody().editAsText()
var url = textElement.setText(range.getValue()).getLinkUrl;
return url
}
But you can't do that because you can't create documents in custom functions.
I'd really like to avoid having to use a triggered script or something instead of a function but I can't work out how to do it without.
Any ideas?

Related

Angular, make links in comments clickable

I am working on an application where user can add comments to certain fields. these comments can also be links. So, as a user I want to be able to click on those links rather than copy pasting them in a new tab.
If a normal web link ([http://|http:]... or [https://|https:]...) occurs in a comment/attribute value, it should be presented as a clickable link.
Multiple links may occur in the same comment/attribute value.
Clicking on a link opens a new browser tab that calls up this link.
This is how the formControl is being managed. I think i can identify multiply links with the help of regex but how do I make them clickable as well?
Thanks for answering and helping in advance.
this.formControl = new FormControl('', [this.params.customValidations(this.params)]);
this.formControl.valueChanges.subscribe(() => {
this.sendStatusToServices();
});
Outside the form editor/input (most likely what you're looking for)
Either before saving the value of the Form Field to the Database, or editing the received body from the database just before presenting to the user, you can use Regex to replace links with anchor tags.
function replaceURLWithHTMLLinks(text) {
var exp = /(\b(https?|ftp|file):\/\/[-A-Z0-9+&##\/%?=~_|!:,.;]*[-A-Z0-9+&##\/%=~_|])/ig;
return text.replace(exp,"<a href='$1'>$1</a>");
}
Rich text editor
If however, you're trying to enable links INSIDE the form input (like WordPress's text editor), that's going to be a bit more difficult. You'll need a <textarea> to enable custom HTML elements. Then you need to detect when the user has typed a URL, so you can call replaceURLWithHTMLLinks(). Honestly, you should just use a package. There's several good one out there.
Angular Rich Text Editor - A WYSIWYG Markdown Editor, by SyncFusion
NgxEditor, by sibiraj-s
typester-editor
Hope this helps
Using a regex approach and a pipe I was able to come up with something like below.
What I'm doing is replacing the links with hyperlink tags using a proper regex.
url replacement regex is taken from here
Supports multiple links within same comment.
Here is the sample pipe code
#Pipe({
name: 'comment'
})
export class CommentPipe implements PipeTransform {
constructor(private sanitizer: DomSanitizer){}
transform(value: any, args?: any): any {
const replacedValue = this.linkify(value);
return this.sanitizer.bypassSecurityTrustHtml(replacedValue)
}
// https://stackoverflow.com/questions/37684/how-to-replace-plain-urls-with-links#21925491
// this method is taken from above answer
linkify(inputText: string) {
var replacedText, replacePattern1, replacePattern2, replacePattern3;
//URLs starting with http://, https://, or ftp://
replacePattern1 = /(\b(https?|ftp):\/\/[-A-Z0-9+&##\/%?=~_|!:,.;]*[-A-Z0-9+&##\/%=~_|])/gim;
replacedText = inputText.replace(replacePattern1, '$1');
//URLs starting with "www." (without // before it, or it'd re-link the ones done above).
replacePattern2 = /(^|[^\/])(www\.[\S]+(\b|$))/gim;
replacedText = replacedText.replace(replacePattern2, '$1$2');
//Change email addresses to mailto:: links.
replacePattern3 = /(([a-zA-Z0-9\-\_\.])+#[a-zA-Z\_]+?(\.[a-zA-Z]{2,6})+)/gim;
replacedText = replacedText.replace(replacePattern3, '$1');
return replacedText;
}
}
Here is the completed stackblitz
If you want links within Input itself you might want to try different approach

Google Apps Script CardService Switch value not in field inputs

The documentation for the Switch class in Google Apps Script suggests that this is the right way to create a switch:
var switchDecoratedText = CardService.newDecoratedText()
.setTopLabel("Switch decorated text widget label")
.setText("This is a decorated text widget with a switch on the right")
.setWrapText(true)
.setSwitchControl(CardService.newSwitch()
.setFieldName("form_input_switch_key")
.setValue("form_input_switch_value")
.setOnChangeAction(CardService.newAction()
.setFunctionName("handleSwitchChange")));
But despite the call to setFieldName() here, when I try this I don't see the switch value in the formInputs object, despite it including everything else on the card.
Is there some way to retrieve the value of a switch here?
I wasn't quite following the documentation - I was calling setFieldName() but not setValue(). Once the switch has a value and is "on", you get a event.commonEventObject.formInputs.form_input_switch_key[""].stringInputs.value which is an array ["form_input_switch_value"]. If the switch is "off", the form_input_switch_key is missing from the formInputs object.

Adding formatted text to a Google Doc

I have a Google Sheet with form responses. I created some code so that each time a form is completed, the results populate a Google Doc. This works fine.
However, I want to add text to my Google Doc as well, which I accomplish using:
function myFunction(e) {
var doc = DocumentApp.create('File');
var text = 'insert text here';
body.appendParagraph(text);
doc.saveAndClose();
}
This text only is added as plain text, however, and I'd like to format this text. Specifically, I'd like to add the text so that it's bolded, underlined, and center-aligned in the document body.
How do I do this?
After some internet searching and SO searching, I tried adding html (e.g., <b> </b>) and I tried text.setBold(true). These approaches did not work.
I'll admit that I know very little about coding in Google Script editor, so I'm not at all sure how to go about this. I'm lucky enough that I got all my form responses to populate a named Google Doc file!
Here's a fragment of a document that I created recently:
var nameStyle={};
nameStyle[DocumentApp.Attribute.FONT_SIZE]=8;
nameStyle[DocumentApp.Attribute.BOLD]=true;
nameStyle[DocumentApp.Attribute.FOREGROUND_COLOR]='#000000';
var valStyle={};
valStyle[DocumentApp.Attribute.FONT_SIZE]=12;
valStyle[DocumentApp.Attribute.BOLD]=false;
valStyle[DocumentApp.Attribute.FOREGROUND_COLOR]='#cc0000';
body.appendParagraph('Basic Project Data').setAttributes(hdg1Style);
var p1=body.appendParagraph(Utilities.formatString('%s: ','PID')).setAttributes(nameStyle);
var p2=body.appendParagraph(Utilities.formatString('%s',selObj.pid)).setAttributes(valStyle);
p2.merge();
for(var i=0;i<basicDataA.length;i++){
var par1=body.appendParagraph(Utilities.formatString('%s: ',basicDataA[i][0])).setAttributes(nameStyle);
var par2=body.appendParagraph(Utilities.formatString('%s',basicDataA[i][1])).setAttributes(valStyle);
par2.merge();
}
Note, the appendParagraph first and then setAttributes.
The above response got me on the right path (Thanks!). Google hasn't documented this feature very well, and some of the features that should work do not. I had found the info on formatting using offsets but that is incredibly tedious and verbose. Here's the full example method that works to insert pre-formatted text into a Google Doc. Hope it helps someone else. Obviously the 2D array can instead be wired up to be fetched from a form, but this will at least show how the rest of the formatting works.
// Open a document by ID.
var body = DocumentApp.openById('YourDocId').getBody();
var authorAffils = [['Tony Tiger',1],['Micky Mouse',2],['Daffy Duck',3],['Elmo Orange',4]];
var nameStyle={};
nameStyle[DocumentApp.Attribute.FONT_SIZE]=11;
// nameStyle[DocumentApp.TextAlignment.Normal]; // This seems to do nothing
nameStyle[DocumentApp.Attribute.FOREGROUND_COLOR]='#000000';
var affilStyle={};
affilStyle[DocumentApp.Attribute.FONT_SIZE]=11;
// affilStyle[DocumentApp.TextAlignment.SUPERSCRIPT]; // This seems to do nothing
affilStyle[DocumentApp.Attribute.FOREGROUND_COLOR]='#cc0000';
for(var i=0;i<authorAffils.length;i++){
var par1=body.appendParagraph(Utilities.formatString(' %s,',authorAffils[i][0])).setAttributes(nameStyle);
var par2=body.appendParagraph(Utilities.formatString('%s',authorAffils[i][1])).setAttributes(affilStyle);
// I am not entirely clear why alignment only works this way whereas font size and color work the other way.
par1.setTextAlignment(DocumentApp.TextAlignment.NORMAL).merge();
par2.setTextAlignment(DocumentApp.TextAlignment.SUPERSCRIPT).merge();
}

Sidebar Javascript Can't find functions in the Library that created the Sidebar

I have a sidebar attached to a Google Doc. I'm using the sidebar to learn more about how Google Docs is structured. I've been using a button click to help me to locate the Body Child Text on the Document itself. When working, this simply moves the Body Child Text into view in the Document and highlights it in yellow for one second.
This is the html and the javascript:
<input id="txtfind0" type="button" value="Click to Find Text" onClick="hlBodyChildText(0)" />
function hlBodyChildText(idx)
{
google.script.run.withSuccessHandler(llBodyChildText).highLightBodyChildText(idx);
}
function llBodyChildText(idx)
{
google.script.run.lowLightBodyChildText(idx);
}
This is the Google Apps Script:
function highLightBodyChildText(idx)
{
var doc=DocumentApp.getActiveDocument();
var child=doc.getBody().getChild(idx);
var position=doc.newPosition(child, 0);
doc.setCursor(position);
child.asText().editAsText().setBackgroundColor('#ffff00');
return idx;
}
function lowLightBodyChildText(idx)
{
Utilities.sleep(1000);
DocumentApp.getActiveDocument().getBody().getChild(idx).asText().editAsText().setBackgroundColor('#ffffff');
}
This was working satisfactorily until I decided to put it all into a library so that I could easily attach it to any document. However it seems that the google.script.run calls require that the functions have to be contained in the script editor of the document. They don't seem to be able to find the functions in the Library.
I tried this approach:
function hlBodyChildText(idx)
{
google.script.run.withSuccessHandler(llBodyChildText).myDocUtilities.highLightBodyChildText(idx);
}
But that just results in the error 'Can't find highLightBodyChildText(idx) of undefined.
So that's when I decided to copy those functions directly from my library into the Code.gs file and it worked immediately.
So the question is: Is there a way to expose these functions to the google.script.run calls without having to copy all of these file into each document.

Changing text attributes (font, size, etc) at the cursor level in a google doc using Google apps script

I would like know if and how it is possible to change text attributes such as font, size, etc. in Google Apps script at the cursor's level. The script is bound to a Google doc file. For example, after running the script, the text font will change for anything written after that point while leaving the text written before unchanged. This is to mimic the way built-in styles or font menus behave in Google docs.
Here is what I came up with so far. It seems to change the text font globally in the document instead of applying the changes only to the text written after running the code. Any suggestions?
var cursor = DocumentApp.getActiveDocument().getCursor();
if(cursor){
var element4 = cursor.getElement()
var body = DocumentApp.getActiveDocument().getBody()
if (element4.editAsText) {
body.editAsText().setFontFamily(DocumentApp.FontFamily.CALIBRI);
}
}
The code below changes the FontFamily for the paragraph in which you select a text... it keeps the same style for all what is coming after and preserves everything before.
If you want to go deeper in precision you'll have to play with offsets and work at text level inside the paragraph but I thought this version could be sufficient.
function setStyle() {
var selection = DocumentApp.getActiveDocument().getSelection();
if (!selection) {
DocumentApp.getUi().alert('Cannot find a selection in the document.');
return;
}
var selectedElements = selection.getSelectedElements();
var element = selectedElements[0].getElement().getParent();
element.setFontFamily(DocumentApp.FontFamily.CONSOLAS);
}
The DocumentApp.FontFamily enumeration is now deprecated. You should use string names, like "Consolas" (case sensitive!), instead.
You can visit the setAttributes section of the DocumentApp Reference found here