How do I insert at a specific position in a Doc? (Inside a text item?) - google-apps-script

My goal is to find the position of some text in a document, delete that text, and put something else its place. I thought I would start by just inserting the new text first, but it doesn't go anywhere near where I thought it would.
The relevant lines of code are here:
matchPosition = theDoc.getBody().findText("put stuff here").getStartOffset();
theDoc.getBody().insertParagraph(matchPosition, "The new stuff");
"put stuff here" is in the middle of a document with all sort of other text and formatting.
I'm guessing this can't be done the way I think it can. Can anyone point me in the right direction? Thanks in advance for your help.

The function you tried using, insertParagraph takes an index as parameter, which is the index of the paragraph, not the place when the text will go.
Instead of appending the text then removing what was there, you could simply replace it
theDoc.getBody().replaceText("put stuff here", "The new stuff");
Or, if you want to place text at a precise position, you could use the function editAsText of the body, and then insertText
matchPosition = theDoc.getBody().findText("put stuff here").getStartOffset();
theDoc.getBody().editAsText().insertText(matchPosition, "The new stuff");
If you want more info, you should check out the complete list of function of the class body here

Related

Docs Inserted Image always before all text

Making a simple app script that puts images and Text into a Google Doc separated by 2 Columns, for whatever reason, no matter the way I try it the images are always above the text (Inline) in the Doc, even though they should be layered (Inline),
//Replace QR Code
let qrText = editLocalBody.findText("{{qrCode}}");
let setImagePlace = qrText.getElement().asText().replaceText("{{qrCode}}", "");
let qrCodeImage = setImagePlace.getParent().asParagraph().insertInlineImage(0, qrCodeBlob);
From what I've seen this should insert an image wherever the text was previously located, but when it runs this it's always in the wrong spot, somehow above the text it was suppost to be in!
//Edit - To Show The Progression Of What Is Suppose To Happen And What Actually Happens:
I'm making QR Code badges for a propriety system that runs integrated tightly with Google, so I'm using appscript to get an entry from a google form containing an amount of badges (With relevent data) and autofill a Google Doc Accordingly.
// Loop Start
I fill my template with a text line that has key words in it I can select and replace later, with a keyword it can use to insert another this (This Part Works)
I first edit (findText("{{qrCode}}");) the QR Code, replacing (.replaceText) the keyword for it to nothing ("")
I then get the parent of the piece of code I ran above, which is a block of text (I think all the text in the Doc, I think this is where the issue lies, it puts it above the text because it's just one 'paragraph' or not multiple 'bodies' of text, if I could separate this I think it would work!) As a paragraph, and insert An Inline Image at Child Index (0, of the image ,qrCodeBlob)
I've debugged this script quite a bit, so I know It's that final line that inserting images fails, it sees all the text as 'one'.
// I want this (In Descending Order, each it's own full line):
Image
Text
Image
Text
//What It Gives Me (In Descending Order, each it's own full line):
Image
Image
Text
Text
let qrCodeImage = setImagePlace.getParent().asParagraph().insertInlineImage(0, qrCodeBlob);

How do I get the position of the end of line character in a google doc

In the google docs add-on quick start, there's a great method to insert text anywhere in the document. It handles well for selections as well as inserting at the cursor, but it has a problem when you "select" the "character" at the end of any line in the doc.
It doesn't actually select anything (or at least nothing is returned from the document's getSelection() method), but when I try to get the position with the document's getCursor() method that returns null as well, so I have no frame of reference to know where the position is on the doc.
Here's an image to show what I mean. Note that it's not a space key being selected; it's a selection you can make at the end of any line in a google doc. Also, note the error, showing that there's no position to use getSurroundingText() on because the getCursor() method returns null.
I need the position right before that selection to insert text, so how would I get this position (if at all possible)?
From the docs:
A representation of the user's selection, or null if the user does not have anything selected in the document, if only the end of a paragraph is selected, if only the end of a paragraph and a new line are selected, or if the script is not bound to the document.
That piece you have selected in the "end of paragraph" that the docs are referring to, so it is returning null exactly as it is defined to do.
I would look into using the getCursor which returns the Position, which can then be used to insertText.
var document = DocumentApp.getActiveDocument();
var position = document.getCursor();
if (position !== null) {
position.insertText("lorem ipsum");
}
Note that this solution would likely force you to simply put your cursor at the end of the line, rather than select the end of paragraph.

Access VBA Create Word header with text and position picture

Having trouble getting access vba to set a word document's header properly. I've got this.
oDoc.PageSetup.DifferentFirstPageHeaderFooter = True
oDoc.Sections(1).Headers(wdHeaderFooterFirstPage).Range.InlineShapes.AddPicture "C:\Users\mr.helpless\Pictures\doody.jpg"
oDoc.Sections(1).Headers(wdHeaderFooterFirstPage).Range.Text = "hello there"
oDoc.Sections(1).Headers(wdHeaderFooterPrimary).Range.Text = "whooo hooo!"
What happens right now is the text will replace the picture for the first page (subsequent pages are fine).
I need to have the picture and text - and I need to offset the picture to the left about half an inch while text is centered with normal margins.
Any idea how to go about it? Basically I need to set a document letterhead with a logo.
Update
Dim myText As String
myText = "hello there"
With oDoc.Sections(1).Headers(wdHeaderFooterFirstPage)
.Shapes.AddPicture Filename:="C:\Users\mr.helpless\Pictures\doody.jpg", LinkToFile:=False, SaveWithDocument:=True
.Range.Collapse
.Range.InsertAfter (myText)
.Range.Font.Name = "Helvetica"
.Range.Font.Size = 8
.Range.Font.Bold = True
.Range.Paragraphs.Alignment = wdAlignParagraphCenter
End With
I've got half of it done, now I just need to position the image to -.5 to margin.
Completed Solution
Just add "Left:=-35" to the picture like such (or whatever value works)
.Shapes.AddPicture Filename:="C:\Users\mr.helpless\Pictures\doody.jpg", LinkToFile:=False, SaveWithDocument:=True, Left:=-35
Have you tried recording a macro in Word that does the rough reposition - then bring the code over to Access and edit it for the correct object and size?
All of it is updated in the original thread. it took using the .Range Collapse to add in text along with the image and it took putting Left:=(value) to move it where I needed it.

(AS3) Getting an HTML-specific character index in a textfield after word wrap

I didn't know how to phrase the title, so sorry about that. If you have a better title suggestion, let me know and I'll change it.
I've got a chunk of text that is displayed as HTML in a TextField. An example of this text is this:
1
<font size="30" color="#FF0000">When your only tool is a hammer, all problems start looking like nails.</font>
</br>
2
<i>99 percent of lawyers give the rest a bad name.</i>
<b>Artificial intelligence is no match for natural stupidity.</b>
<u>The last thing I want to do is insult you. But it IS on the list.</u>
</br>
3<showimage=Images/image1.jpg>
I don't have a solution, but I do admire the problem.
The only substitute for good manners is fast reflexes.
Support bacteria - they're the only culture some people have.
</br>
4
Letting the cat out of the bag is a whole lot easier than putting it back in.
Well, here I am! What are your other two wishes?
Most of the tags are basic, meant to display what I can do formatting wise. However, since Adobe Air has a sandbox that prevents inline images (via the <img src='foo.png'> tag), I've had to come up with another way to display images.
Basically, I intend on having an image displayed somewhere on the screen, and as the user scrolls the image will change based on where in the text they have scrolled to. The image can be a background image, a slideshow on the right, anything really.
In the snippet above, look for my custom tag <showimage=Images/image1.jpg>. I want to get the local y position of that tag once the TextField is rendered as HTML and word wrapped. The trouble is, when I query the y position of the tag (using getCharBoundaries), I can only either search for the tag when I render the text as a .text instead of a .htmlText. If I search for the tag in the TextField after rendering it as .htmlText, it doesn't get found because the tags are hidden and replaced with formatting.
The trouble with the y value I get before rendering the HTML is that the y value will be different due to font sizes, tags being hidden and word wrap changing the line and y value that the tag is located at.
How do I get the correct y value of an HTML tag once the HTML has been rendered?
I've considered using a different style tag, maybe something like &&&&&showImage=Images/image1.jpg&&&&, but that seems like a cop-out and I'd still run into problems if multiple of those tags were in a block of text and the tags were removed, followed by word wrap that shifts lines in a pretty unpredictable way.
myTextField.textHeight tells you the height of the text in pixels. So you can split the string on whatever you're looking for, put the text before your target in the textField and get the textHeight, then put the rest of the text in.
Here's some example code - tMain is the name of the textField:
var iTextHeight: int = 0;
var sText: String = '<font size="30" color="#FF0000">When your only tool is a hammer, all problems start looking like nails.</font></br><i>99 percent of lawyers give the rest a bad name.</i><b>Artificial intelligence is no match for natural stupidity.</b><u>The last thing I want to do is insult you. But it IS on the list.</u></br><showimage=Images/image1.jpg> I don\'t have a solution, but I do admire the problem. The only substitute for good manners is fast reflexes. Support bacteria - they\'re the only culture some people have. </br>Letting the cat out of the bag is a whole lot easier than putting it back in. Well, here I am! What are your other two wishes?';
var aStringParts: Array = sText.split("<showimage=Images/image1.jpg>");
for (var i = 0; i < aStringParts.length; i++) {
if (i == 0) {
tMain.htmlText = aStringParts[i];
trace("height of text: " + tMain.textHeight);
} else {
tMain.appendText(aStringParts[i]);
}
}
sText gets split on the tag you're looking for (removes the text you're looking for and breaks remaining text into an array). The text leading up to the tag is put in the textField and the textHeight is traced. Then the rest of the text is put in the textField. This gives you the y pixel number you need to arrange things.
Let me know of any questions you have.
Instead of going through the trouble of parsing your image tag, have you tried playing with HTMLLoader and using the loadString method? This should load everything in its proper place including the image using the img tag.
private var htmlLoader:HTMLLoader;
private function loadHtml(content:String):void
{
htmlLoader = new HTMLLoader(); //Constructor
htmlLoader.addEventListener(Event.COMPLETE, handleHtmlLoadComplete); //Handle complete
htmlLoader.loadString(content); //Load html from string
}
private function handleHtmlLoadComplete(e:Event):void
{
htmlLoader.removeEventListener(Event.COMPLETE, handleHtmlLoadComplete); //Always remove event listeners!
htmlLoader.width = htmlLoader.contentWidth; //Set width and height container
htmlLoader.height = htmlLoader.contentHeight;
addChild(htmlLoader); //Add to stage
}
Another approach is to search your html string for <showImage ..> tags and replace these with shortcodes e.g [showImage ..] , before inserting the htmlString in a textField. Then this is NOT xml but text and you can retrieve the y value (that is if i understand correctly your issue).
Then the rest of your code can take it from there.
(ps using HtmlLoader seems nice alternative though)

Receiving click events from separate lines with AS3

I want to receive separate click events from separate lines in a text field, and every time a certain line is clicked by the user, I would like to highlight it and have an event happen.
I would ideally like this to happen with dynamic text, and not have to break the text apart by hand. Using the htmlText property is an option, but I am unsure as to how to bind clickEvents to separate elements.
Where do I begin?
There is no ready to use solution for this. But you can make it yourself using a few things:
set CLICK listener for the whole text field
listen for click and check the caretIndex property
use getLineIndexOfChar to check what's the line of the current caret position
use getLineOffset and getLineLength to get the position of the first and last character of that line
use setSelection to highlight this line
There might be some faster and easier way, but this is what works for sure :)
EDIT: decided to post the solution code, as I was wondering how exactly it works.. and it would be a shame to just leave it unpublished and make you do it instead :)
field.addEventListener(MouseEvent.CLICK, onTfClicked);
function onTfClicked(e:MouseEvent):void {
trace (field.caretIndex);
var line:uint = field.getLineIndexOfChar(field.caretIndex);
var start:uint = field.getLineOffset(line);
var end:uint = start + field.getLineLength(line);
field.setSelection(start, end);
}