Currently quill editor will save the image in base64 image format. That is fine for now.
But how do I make sure quill save the base64 content only and without those formatting?
This is how it would look like after the image has been saved in the db.
<p><img src="data:image/png;base64,iVBXXXXXXXXXXXXXXXXXXXXXXXXXXX"></p>
Basically I want to strip off "< p >" and < img src= tags.
I would like to retain data:image/png;base64,iVBXXXXXXXXXX only. Is there any setting that I can do on quill modules?
If slicing the string is a doable approach, something like this should work for your current format:
var str = '<p><img src="data:image/png;base64,iVBXXXXXXXXXXXXXXXXXXXXXXXXXXX"></p>'
var srcPosition = str.indexOf('src');
var pEndPosition = str.indexOf('</p>');
var strippedString = str.slice(srcPosition + 5, pEndPosition - 2);
Good luck!
Not sure about modules but you could use something something like the below to get all the images into an array:
function GetImageData(str) {
var retArray = [];
var regexPattern = /src="([^"]+)/gi;
var matches = str.match(regex);
for (var i = 0;i < matches.length;i++) {
retArray.push(matches[i].replace('src="',''));
}
return retArray;
}
var test = '<p><img src="data:image/png;base64,iVBXXXXXXXXXXXXXXXXXXXXXXXXXXX"></p><p><img src="data:image/png;base64,iVBYYYYYYYYYYYYYYYYYYYYYYYYYYY"></p><p><img src="data:image/png;base64,iVBZZZZZZZZZZZZZZZZZZZZZZZZZZZ"></p>';
var result = GetImageData(test);
This gives you an array with the following:
"data:image/png;base64,iVBXXXXXXXXXXXXXXXXXXXXXXXXXXX"
"data:image/png;base64,iVBYYYYYYYYYYYYYYYYYYYYYYYYYYY"
"data:image/png;base64,iVBZZZZZZZZZZZZZZZZZZZZZZZZZZZ"
Related
I am trying to populate a page with firebase data.
This is my firebase data structure...
What I want is to create number of divs according to the number of posts in firebase. And in the divs with title and subtitle in h2 tag and p tag.
I am new to firebase soo any help would be appreciated...
and also i want to limit the number of divs to 4 starting from the latest post.
this is my java script
firebase.initializeApp(firebaseConfig);
var postsRef = firebase.database().ref("posts").orderByKey();
postsRef.once("value").then(function (snapshot) {
snapshot.forEach(function (childSnapshot) {
var key = childSnapshot.key;
var childData = childSnapshot.val();
var name_val = childSnapshot.val().title;
var id_val = childSnapshot.val().subtitle;
console.log(name_val);
var post = document.getElementById('#tst-post');
var divh2 = document.createElement('h2');
divh2.innerText - childData.val().title + "---" + JSON.stringify(childData.val());
$(post).append(divh2);
});
});
i dont know what i am doing in this code, I just watched some tutorials. Please help me.
You are not very far from a result.
By searching on the internet (https://www.google.com/search?client=firefox-b-d&q=how+to+dynamically+create+div+in+javascript) you can easily find a lot of examples on how to create DIVs dynamically. For example: https://stackoverflow.com/a/50950179/3371862
Then, in the Firebase Realtime Database documentation you find how to filter data and in particular how to "Sets the maximum number of items to return from the end of the ordered list of results" with limitToLast().
So if you put all of that together as follows, it should do the trick:
<script>
var postsRef = firebase
.database()
.ref('posts')
.orderByKey()
.limitToLast(4);
postsRef.once('value').then(function(snapshot) {
snapshot.forEach(function(childSnapshot) {
var key = childSnapshot.key;
var childData = childSnapshot.val();
var name_val = childSnapshot.val().title;
var id_val = childSnapshot.val().subtitle;
createDiv(name_val, id_val);
});
});
function createDiv(title, subtitle) {
var myDiv = document.createElement('DIV'); // Create a <div> node
var myTitle = document.createTextNode(title); // Create a text node
myDiv.appendChild(myTitle); // Append the text
var mySubtitle = document.createTextNode(subtitle); // Create a text node
myDiv.appendChild(mySubtitle); // Append the text
myDiv.style.backgroundColor = 'grey';
myDiv.style.border = 'solid';
myDiv.style.margin = '10px';
document.body.appendChild(myDiv);
}
</script>
I would like to remove all tags that start with href="http: and leave the text being linked in place for each of them.
There are other tags in my html file that I don't want changed at all. Again, I only want the tags that start with http stripped with the text being linked staying in place.
Essentially I want all external links stripped from the html document and the internal links to remain intact.
Any help with the right Find What: and Replace with: information would be appreciated!
You could remove all tags that don't contain the current host:
const links = Array.from(document.getElementsByTagName('a'))
links.forEach(elm => {
!elm.href.includes(window.location.host) && elm.parentNode.removeChild(elm);
})
google
about
no need for JQuery
A solution could be something like
jQuery( document ).ready( function($) {
//stores all a tags in an array.
var aTags = document.getElementsByTagName("a");
var re = new RegExp("^http://");
var length = aTags.length;
for(var i = 0; i < length; i++) {
if( aTags[i].href.test(re) ) {
aTags[i].href = "https://" //reset to something else if true?
//OR
aTags[i].href.replace("http://", "https://"); //replace with https
}
}
});
The following JavaScript should replace all links with the text, they contain:
var links = document.getElementsByTagName("a");
var regEx = /^https?:\/\//;
for (var i = 0; i < links.length; i++)
{
var elem = links[i];
if (elem.href.test(regEx))
{
var node = document.createTextNode(elem.textContent);
elem.parentElement.replaceChild(node, elem);
}
}
It loops through all links and if they start with 'http://' or 'https://', a textnode is created with the text, and that textnode replaces the link.
This question was cross-posted to Web Applications: Help me find my Element in a Google Doc so I can act on it in script?
Here is my Google Doc:
https://docs.google.com/document/d/1TgzOIq0g4DyDefmJIEnqycDITIx_2GNQkpdxMGwtqB8/edit?usp=sharing
You can see a button in it titled ENTER NEW NOTE.
I have been successful at rolling through the elements of the doc to find the table and to replace txt in those areas as needed. But the button here needs to have the URL changed, and I cannot figure out how to do it.
This URL seems to give an idea, but I cannot turn it into my answer since I don't quite understand. Mail merge: can't append images from template
Would someone help me with this to the point of showing the actual code, because I have tried to edit the many examples found about elements, setURL and looking to parent, etc. I just end up with a mess.
I am calling the script from a Google Sheet, to wok on a BUNCH of Google Docs. (I will be running through the spreadsheet to get URL's for the next doc to have it's URL replaced.
Here is as close as I believe I have gotten:
function getDocElements() {
var doc = DocumentApp.openByUrl("https://docs.google.com/document/d/1TgzOIq0g4DyDefmJIEnqycDITIx_2GNQkpdxMGwtqB8/edit?usp=sharing"),
body = doc.getBody(),
numElements = doc.getNumChildren(),
elements = [];
for (var i = 0; i < numElements; ++i){
var element = doc.getChild(i),
type = element.getType();
// daURL = element.getURL();
// Look for child elements within the paragraph. Inline Drawings are children.
// if(element.asParagraph().getNumChildren() !=0 && element.asParagraph().getChild(0).getType() == DocumentApp.ElementType.INLINE_DRAWING) {
var drawingRange = body.findElement(DocumentApp.ElementType.INLINE_DRAWING);
while (drawingRange != null) {
var element = drawingRange.getElement();
var drawingElement = element.asInlineDrawing();
//drawingElement.removeFromParent();
drawingElement.setURL("http://www.google.com");
drawingRange = body.findElement(DocumentApp.ElementType.INLINE_DRAWING);
}
// For whatever reason, drawings don't have their own methods in the InlineDrawing class. This bit copies and adds it to the bottom of the doc.
//var drawing = element.asParagraph().copy();
//body.appendParagraph(drawing);
}
Logger.log(i + " : "+type);
}
Here is my newest iteration that shows in the logs the elements, including the inLineDrawing I want to change...
===========
function getDocElement() {
var doc = DocumentApp.openByUrl("https://docs.google.com/document/d/1TgzOIq0g4DyDefmJIEnqycDITIx_2GNQkpdxMGwtqB8/edit?usp=sharing"),
body = doc.getBody(),
numElements = doc.getNumChildren(),
elements = [];
for (var i = 0; i < numElements; ++i){
var element = doc.getChild(i),
type = element.getType();
// daURL = element.getURL();
Logger.log(i + " : " + numElements + " : "+ type + " " + element);
// Search through the page elements. Paragraphs are top-level, which is why I start with those.
if( type == DocumentApp.ElementType.PARAGRAPH ){
// Look for child elements within the paragraph. Inline Drawings are children.
if(element.asParagraph().getNumChildren() !=0 && element.asParagraph().getChild(0).getType() == DocumentApp.ElementType.INLINE_DRAWING) {
//element.getParent().setLinkUrl("http://www.google.com");
Logger.log(element.asParagraph().getChild(0).getType() + " : " + element.getAttributes());
// For whatever reason, drawings don't have their own methods in the InlineDrawing class. This bit copies and adds it to the bottom of the doc.
var drawing = element.asParagraph().copy();
//body.appendParagraph(drawing);
// body.appendParagraph();
if(element.getParent() !=''){
//element.asParagraph().appendHorizontalRule();
//element.editAsText().appendText("text");
// element.getParent().insertHorizontalRule(0);
}
}
}
}
}
I'm not sure why the setLinkUrl() is not available for InlineDrawing 🤔
If you can replace your drawing with an image (You can download your drawing as png or svg and insert it), you will be able to use setLinkUrl
Here is an example:
function myFunction() {
var body = DocumentApp.getActiveDocument().getBody();
// All inline images as a RangeElement
var images = body.findElement(DocumentApp.ElementType.INLINE_IMAGE);
// select first image, in case your doc has more than one you'll need to loop
var element = images.getElement();
var image = element.asInlineImage();
image.setLinkUrl("www.google.com");
}
Unfortunately the Class InlineDrawing doesn't have methods to access the attached links nor any other to programmatically change it to a InlineImage1. It looks to me that you will have have to make the link changes manually.
Related Feature requests:
Issue 3367: Allow exporting InlineDrawing as an image
Issue 1054: Add ability to create and modify drawings
References
1: Answer by Henrique Abreu to Modifying a drawing using Google Apps Script
*I have a Google Document with a string like "text {logo} text"
How do place an image where {logo} is?
So far I tried:
var logoElement = s.findText("{logo}").getElement();
logoElement.getParent().insertInlineImage(0,logoBlob);
s.replaceText("{logo}", "");
But this inserts the image before the found paragraph (or with 1: after). How do I place it inside the paragraph at the exact location?
I hope will be helpful, The following code is fine to me.
function insertImage(doc) {
// Retrieve an image from the web.
var resp = UrlFetchApp.fetch("http://www.google.com/intl/en_com/images/srpr/logo2w.png");
var image = resp.getBlob();
var body = doc.getBody();
var oImg = body.findText("<<Logo1>>").getElement().getParent().asParagraph();
oImg.clear();
oImg = oImg.appendInlineImage(image);
oImg.setWidth(100);
oImg.setHeight(100);
}
Thanks to the comment from Serge and the original post of the link for pointing me in the right direction.
Here's what I have now:
var s = d.getHeader();
var logoResult = s.findText("{logo}"); // search result
var logoElement = logoResult.getElement(); // the paragraph that contains the placeholder
var text = logoElement.getText();
var placeholderStart = logoResult.getStartOffset(); // character position start placeholder
var placeholderEnd = logoResult.getEndOffsetInclusive(); // char. position end placeholder
var parent = logoElement.getParent();
var parPosition = parent.getChildIndex(logoElement);
// add new paragraph after the found paragraph, with text preceding the placeholder
var beforeAndLogo = s.insertParagraph(parPosition+2, text.substring(0, placeholderStart));
var logo = beforeAndLogo.appendInlineImage(logoBlob); // append the logo to that new paragraph
// add new paragraph after the new logo paragraph, containing the text after the placeholder
var afterLogo = s.insertParagraph(parPosition+3, text.substring(placeholderEnd+1));
afterLogo.merge(); // merge these two paragraphs
// finally remove the original paragraph
parent.removeFromParent(); // remove the original paragraph
It is not complete, I should also copy all the attributes.
More importantly, it does not copy the tab settings (e.g. center tab). Have not found a way to set tab positions.
I tried a simpler version based on your answer that keeps the format of the original paragraph...
Give it a try, it's not "foolproof" but it works in my test and is (I think) an interresting trial ;-)
code here :
function test(){
placeImage('{logo}','0B3qSFd3iikE3SkFXc3BYQmlZY1U');
//This is my page and I’d like to have a {logo} on it right here
}
function placeImage(placeHolder,imageId) {
var logoBlob = DocsList.getFileById(imageId).getBlob();
var d = DocumentApp.getActiveDocument()
var s = d.getHeader();
var logoResult = s.findText(placeHolder);
var placeholderStart = logoResult.getStartOffset();
var par = s.getChild(0).asParagraph();
var parcopy = par.copy();
var parLen = par.editAsText().getText().length-1;
Logger.log('placeholderStart = '+placeholderStart+' parLen = '+parLen)
par.editAsText().deleteText(placeholderStart, parLen);
parcopy.editAsText().deleteText(0, placeholderStart+placeHolder.length);
var img = s.getChild(0).appendInlineImage(logoBlob);
s.appendParagraph(parcopy);
parcopy.merge();
}
My goal is to parse a TableOfContents element in a Google Document and write it to another one. I want to do this for every document in a folder.
Having gone to the bother of converting each document to the type generated by DocsList just so I can use this method [ which a document generated by DocumentApp does not have. Why, I don't understand, because otherwise the two 'documents' are similar when it comes to finding parts. ], I find that what I get back is a SearchResult. How is this elusive construction used? I've tried converting it into a TableOfContents element [ ele = searchResult.asTableOfContents() ], which does not error out, but nothing I do allows me parse through its child elements to recover their text works. Interestingly enough, if you get a TableOfContents element by parsing through the document's paragraphs to get it, THAT let's you parse the TOC.
Would someone speak to this question. I sure would appreciate a code snippet because I'm getting nowhere, and I have put some hours into this.
The asTableOfContents() method is only there to help the editor's autocomplete function. It has no run-time impact, and cannot be used to cast to a different type. (See ContainerElement documentation.)
To parse the table of contents, start by retrieving the element from the SearchResult. Below is an example that goes through the items in a document's table of contents to produce an array of item information.
Example Document
Parsing results
On a simple document with a few headings and a table of contents, here's what it produced:
[13-08-20 16:31:56:415 EDT]
[
{text=Heading 1.0, linkUrl=#heading=h.50tkhklducwk, indentFirstLine=18.0, indentStart=18.0},
{text=Heading 1.1, linkUrl=#heading=h.ugj69zpoikat, indentFirstLine=36.0, indentStart=36.0},
{text=Heading 1.2, linkUrl=#heading=h.xb0y0mu59rag, indentFirstLine=36.0, indentStart=36.0},
{text=Heading 2.0, linkUrl=#heading=h.gebx44eft4kq, indentFirstLine=18.0, indentStart=18.0}
]
Code
function test_parseTOC() {
var fileId = '--Doc-ID--';
Logger.log( parseTOC( fileId ) );
}
function parseTOC( docId ) {
var contents = [];
var doc = DocumentApp.openById(docId);
// Define the search parameters.
var searchElement = doc.getBody();
var searchType = DocumentApp.ElementType.TABLE_OF_CONTENTS;
// Search for TOC. Assume there's only one.
var searchResult = searchElement.findElement(searchType);
if (searchResult) {
// TOC was found
var toc = searchResult.getElement().asTableOfContents();
// Parse all entries in TOC. The TOC contains child Paragraph elements,
// and each of those has a child Text element. The attributes of both
// the Paragraph and Text combine to make the TOC item functional.
var numChildren = toc.getNumChildren();
for (var i=0; i < numChildren; i++) {
var itemInfo = {}
var tocItem = toc.getChild(i).asParagraph();
var tocItemAttrs = tocItem.getAttributes();
var tocItemText = tocItem.getChild(0).asText();
// Set itemInfo attributes for this TOC item, first from Paragraph
itemInfo.text = tocItem.getText(); // Displayed text
itemInfo.indentStart = tocItem.getIndentStart(); // TOC Indentation
itemInfo.indentFirstLine = tocItem.getIndentFirstLine();
// ... then from child Text
itemInfo.linkUrl = tocItemText.getLinkUrl(); // URL Link in document
contents.push(itemInfo);
}
}
// Return array of objects containing TOC info
return contents;
}
Bad news
The bad news is that you are limited in what you can do to a table of contents from a script. You cannot insert a TOC or add new items to an existing one.
See Issue 2502 in the issue tracker, and star it for updates.
If you can post code or explain your issue with DocsList vs DocumentApp, it could be looked at. The elements of a Google Document can only be manipulated via DocumentApp.
I modified the above code to re-create the TOC in a table only with the desired levels(i.e. h1, h2). The only caveat is that TOC must be present & updated before running this.
function findToc(body, level = 2) {
const indent = 18;
let contents = [];
const tocType = TABLE_OF_CONTENTS;
const tocContainer = body.findElement(tocType);
if (tocContainer) {
// TOC was found
const toc = tocContainer.getElement().asTableOfContents();
const totalLines = toc.getNumChildren();
for (let lineIndex = 0; lineIndex < totalLines; lineIndex++) {
const tocItem = toc.getChild(lineIndex).asParagraph();
const { INDENT_START } = tocItem.getAttributes();
const isDesiredLevel = Number(INDENT_START) <= indent * (level - 1);
if (isDesiredLevel) {
contents.push(tocItem.copy());
}
}
}
return contents;
}
function addToTable(cellText) {
body = DocumentApp.openById(docId).getBody();
const table = body.appendTable();
const tr = table.insertTableRow(0);
const td = tr.insertTableCell(0);
cellText.forEach(text => {
td.appendParagraph(text);
})
}
function parseTOC(docId) {
body = DocumentApp.openById(docId).getBody();
const contents = findToc(body);
addToTable(contents);
}