Convert html/css to google doc and keep styles as close as possible - google-drive-api

Right now I am able to create a new text/html document and add some html to it with google drive API. That part looks like this:
await drive.files.create({
//request body has html/text mime type
requestBody: body.requestBody,
fields: 'id',
}, async function (err: any, file: any) {
if (err) {
console.error(err);
} else {
//update adds media with html content
await drive.files.update({
fileId: file.data.id,
media: body.media,
});
}
After that I am converting the file to a google doc like this but some of the formatting is lost.
await drive.files.copy(
{
fileId: file.data.id,
requestBody: {
name: file.data.name,
mimeType: "application/vnd.google-apps.document"
}
}
);
The formatting will keep h1 and h2 etc, making the headings bold and different sizes, but all other formatting is lost.
I do not need the formatting to be perfect, but I need it to be close. Is there any work around for this?
Maybe re-add styles after the document is converted, or create a template or something like that?
Or something else I am missing?
The required formatting will be simple, things like centering and sizing images, font sizes, etc.
Any help is appreciated, thanks!

Related

Gatsby mdx pages not rendering fully when placed in subfolder of src/pages

I have been converting a WordPress site to Gatsby, and everything works nicely with gatsby develop, however after building with gatsby build some pages seem to render with only the page body and no wrapper layout or styling. I am using markdown pages with mdx, and I have all my markdown files under subfolders of the src/pages directory, like this:
src/pages/
--project/
--contact.md
--outputs.md
--project.md
--sources.md
--software/
--apps.md
--frontend.md
--system.md
The above structure is more for organizational reasons than anything else (there are many more mdx files in reality). It does also correspond to the overall path structure of the site, however. In my built site, when I go to http://localhost:9000/contact the page renders perfectly, but when I visit http://localhost:9000/project or any other pages relating to that folder I only see the page body (the text content), with no layout component wrapper or styling. Everything under the software folder renders fine.
Each markdown file has a slug defined in the usual way in the frontmatter. The slug defined in src/project/project.md is just '/project'. The slug for src/project/contact.md is '/project/contact'.
Clearly the presence of src/pages/project/project.md is causing problems, but I can't figure out exactly why. I tried renaming that to src/pages/project/index.md, but that did nothing. Interestingly, when I look at public/project I see an index.html at the top level, with subfolders for each subpage, each containing its index.html. For public/software there is no index.html at the top level.
My gatsby-config.js (relevant parts):
{
resolve: `gatsby-source-filesystem`,
options: {
name: `pages`,
path: `${__dirname}/src/pages`,
},
},
{
resolve: `gatsby-plugin-mdx`,
options: {
extensions: [`.md`, `.mdx`, `.markdown`],
gatsbyRemarkPlugins: [
{
resolve: `gatsby-remark-images`,
options: {
maxWidth: 1024,
},
},
],
},
},
My template (under templates/page.js - I use some MUI components):
export default function SitePageTemplate({ data: { mdx } }) {
const { frontmatter, body } = mdx;
const { title } = frontmatter;
return (
<Layout>
<Seo title={title} />
<Container fixed>
<Stack direction="row" justifyContent="space-between">
<SideBar/>
<div style={ { padding: "0 0 0 3.5%", width: "75%" } }>
<MDXRenderer>{body}</MDXRenderer>
</div>
</Stack>
</Container>
</Layout>
);
}
export const pageQuery = graphql`
query ($id: String!) {
mdx(id: { eq: $id }) {
body
frontmatter {
date(formatString: "MMMM DD, YYYY")
slug
title
}
}
}`
My gatsby-node.js:
const path = require("path");
exports.createPages = async ({ graphql, actions, reporter }) => {
const { createPage } = actions
createPage({
path: "/using-dsg",
component: require.resolve("./src/templates/using-dsg.js"),
context: {},
defer: true,
})
const result = await graphql(`
query MARKDOWN {
allMdx {
edges {
node {
id
frontmatter {
date(formatString: "MMMM DD, YYYY")
slug
title
}
}
}
}
}
`);
if (result.errors) {
reporter.panicOnBuild("🚨 ERROR: Loading \"createPages\" query");
}
const md = result.data.allMdx.edges;
md.forEach(({ node }, index) => {
createPage({
// This component will wrap our MDX content
component: path.resolve("./src/templates/page.js"),
// Pass any value you want to access inside the template. They'll be available via `props`.
context: {
id: node.id
},
// Slug defined with frontmatter in each MDX file.
path: node.frontmatter.slug
});
});
}
If I place all the markdown files flat under the src/pages directory the problem goes away. But I would like to retain the above folder layout so that the markdown is organized properly. How can I do this whilst at the same time avoiding this problem?
OK, returning to this issue after a few months, I think I finally solved it. A warning I was also getting turned out to be the real clue - initially I had thought it unrelated to this issue. At develop and at build time I was getting a warning in the following format:
warn Non-deterministic routing danger: Attempting to create page: "/project/contact/", but page
"/project/contact" already exists
Others have reported this warning, but none of the reasons or propsed fixes seemed to relate to my problem. Looking at my gatsby-config.js, however, I noticed that I had at some time included the gatsby-plugin-page-creator plugin. I suspected that somehow this might be generating pages in addition to the mdx plugin. And it seemed as if this was right - removing the plugin removed both the warnings about duplicate page creation and also fixed my rendering problems. Everything looks fine now, for both development and production versions of my site.
I can't remember why I originally included this plugin - I was originally using the mdx extension for my markdown files, and I think I needed gatsby-plugin-page-creator so that files with that extension would be correctly interpreted as markdown. I now use the standard md extension, and removing gatsby-plugin-page-creator doesn't cause any problems.

Looping through JSON array from an API, can get all results or none result, no luck with loops, using jQuery

I'm just trying something new out to get skills more up to date, and am a bit stumped on this jQuery API response. I have all of the results going to console fine, I have them displaying on an html file, but all together as one. I want to put a break between each word (it's [Words API][1] and I'm stuck. I usually use PHP, but well, it's not practical for what I'm planning. Here is the code, and I'll show the best I can in results. Thank you!
<div id="div1">
// This is where it shows up as "unmitigated,butcherly,crimson,gory,homicidal,internecine"
</div>
<script>
const settings = {
"async": true,
"crossDomain": true,
"url": "https://wordsapiv1.p.rapidapi.com/words/bloody/similarTo",
"method": "GET",
"headers": {
"x-rapidapi-key": "<my key>",
"x-rapidapi-host": "<host>"
}
};
$.ajax(settings).done(function (response) {
console.log(response);
$("#div1").html(response.similarTo + " "); // This puts a comma between each word, but no spacing, when I want a line break. I need to be able to customize results, make them links, add styles, etc.
});
Thank you so much! Only 3 more weeks of strict "stay at home" Covid19 orders. I'm learning a lot!
I guess you have a text string in response.similarTo containing a mess of comma-separated words.
You can process them like this. Split breaks them at commas. The rest of this code formats them into an HTML list and displays them.
const results = []
const words = response.similarTo.split(',')
for (const word of words) {
/* do what you will with each word in turn, for example... */
results.push('<li>' + word + '</li>')
}
$("#div1").html('<ol>' + results.join('') + '</ol>')

Flask with Summernote And Adding An image - Grabbing The Proper Data?

So im trying to get the information thats being grabbed via summernote textarea. When im not adding an image, everything works perfectly fine and I see the html content from the text editor.
But when I upload a picture, it suddenly gets stuck in a loop??? There more functionality that actually adds the info into the DB, and the image with that ridiculous img src, is saved, but for some reason its iterating the img src over and over? Since then Ive had everything commented out, only to print the textfield content, and for some reason, still get hit with an endless loop the moment I click the submit button? Any help is appreciated, thanks.
flask.py
#app.route("/update", methods=["POST"])
def update():
# Grab Text editor content from form:
contentInfo = request.form["content"]
print("TEST HERE", contentInfo)
html:
<form action="/update" method="POST">
<h1 style="text-align:center">content</h1><textarea name=content id="summernote">{{value}</textarea>
<input class="input-btn" type="submit" value="Update">
</form>
Script init inline within html:
<script>
$(document).ready(function() {
$('#summernote').summernote({
height: 300,
minHeight: null,
maxHeight: null,
focus: true,
onImageUpload: function(files, editor, welEditable) {
sendFile(files[0],editor,welEditable);
}
});
});
</script>
So the text editor and everything works perfect, but the moment I add an image and click submit, my terminal gets stuck in an endless loop, literally need to trash the terminal in order to get it to stop before it crashes.
Any advice is appreciated, thanks.
Results: Over and Over...
Well Stack over flow wouldnt let me post an example, but it was just a bunch of what looked like the img src code from summernote over and over
Update: - So I changed a few things and at least got it to stop looping. I guess it was never looping what it was doing is literally printing out the content of whats being grabbed and apparently its a bunch of crap. I then instead trying to print it with certain params such as "content["img"] only to find out it was slices, so this is apparently an array: But I throw it into type, and it comes back with a class of "bytes" and a length of 529288.... lol! SO the printing wasnt a loop, it was literally printing the 500k lines of this stupid conversion... (super dumb that summernote compiles their images this way in my opinion)
Anyways, Wanted to post the current changes, I feel I am starting to get some progress as it is no longer stuck trying to print out 500k lines. Obviously the data thats being grabbed is the overall app converted into byes? becuase I feel the image conversion is around 7k characters, not 500k...
I feel my issue may be how im trying to grab the data? Since my app is flask and python, it has been a trial an error process trying to get it to work together with the inline javascript. So how my logic works here, is the moment a image is dropped into summernote, it gets thrown into the python logic "updateTest" All im trying to do here, is just grab the image data, so that I can manipulate and do as I wish with the results. How to go about properly grabbing this info? Any advice or insight is appreciated, thanks.
Updated Code:
html:
<form action="/updateTest" method="POST">
<h1 style="text-align:center">content</h1><textarea name=content id="summernote">{{value}</textarea>
<input class="input-btn" type="submit" value="Update">
flask.py:
#app.route("/updateTest", methods=["POST"])
def updateTest():
content = request.get_data()
print("test here", type(content))
print("test here2", len(content))
inline javascript within HTML:
$(document).ready(function() {
$('#summernote').summernote({
height: 300,
focus: true,
callbacks: {
onImageUpload(files) {
sendFile(files[0], data => {
let imgNode = document.createElement("img");
imgNode.setAttribute('src', data.url)
$(this).summernote('insertNode', imgNode);
})
}
}
});
});
var sendFile = function(file, callback) {
var data;
data = new FormData();
data.append("file", file);
return $.ajax({
url: "/updateTest",
data: data,
cache: false,
contentType: false,
processData: false,
type: 'POST',
success: function(data) {
return callback(data);
}
});
};
Any help on how to properly pull this file/image data is really what im looking for right now. Any help is appreciated, thanks
So I finally figured it out. Here is the proper code. now I originally wanted this to work with S3 buckets so in the end, going to that route right off the bat, rather than dealing with the crappy conversion summernote tries to do, I recommend everyone else doing the same thing when coming to something like this:
html:
<form action="/updateTest" method="POST">
<h1 style="text-align:center">content</h1><textarea name=content id="summernote">{{value}</textarea>
<input class="input-btn" type="submit" value="Update">
inline javascript within html:
<style>
$(document).ready(function() {
$('#summernote').summernote({
height: 300,
focus: true,
callbacks: {
onImageUpload(files) {
sendFile(files[0], data => {
let imgNode = document.createElement("img");
imgNode.setAttribute('src', data.url)
$(this).summernote('insertNode', imgNode);
})
}
}
});
});
var sendFile = function(file, callback) {
var data;
data = new FormData();
data.append("file", file);
return $.ajax({
url: "/addImgSummer",
data: data,
cache: false,
contentType: false,
processData: false,
type: 'POST',
success: function(data) {
return callback(data);
}
});
};
</style>
flask.py:
#app.route("/addImgSummer", methods=["POST"])
def addImgSummer():
#Grabbing file:
img = request.files["file"] #<------ THIS LINE RIGHT HERE! Is #literally all I needed lol.
# Below is me replacing the img "src" with my S3 bucket link attached, with the said filename that was added.
imgURL = "https://"+ S3_BUCKET_NAME +".s3.amazonaws.com/images/"+ img.filename
return jsonify(url = imgURL)
NOTE I have logic elsewhere that adds the data to the S3 bucket, the code above simply renders the result from my bucket. I plan on uploading my code to stack overflow on how to do a full s3 bucket situation with summernote. As this right here was just to finish the conclusion of my initial "Being stuck"
Anyways, hope this helps anyone who gets stuck where I did, as there is literally no proper documentation on how to utilize summernote with flask...(Dont get me wrong theres a lot, but none that work..) And even more so, NONE that utilize a better method than converting your image into a 7k byte character sequence, as I see most people doing... Just saving that horrid crap in their DB... So nothing properly working, at least not that I've found the past 3 days of searching..This right here, is the only working solution Ive come across.
The main confusion lies with mixing the javascript in the front end, and talking with your flask/python backend. Once you now how to grab that data, its smooth sailing.

How can I display dynamic HTML having Vue variables inside?

I am trying to make the page content dynamic. I am using ck-editor in which i added html content and used the same vue variables inside it which i declared in the vue file where i want to show ck-editor data. I found a similar post vuejs - “editing” html inside variable
which works fine if i write the html inside a variable. But in my case, i am saving data in database. It is saving properly with html tags, without converting the tags. When i get data using axios it returns it in form of string. And i used vue variable to display that html.
Here is my code for better understanding:
<div v-html="htmlText"></div>
new Vue({
el: '#app',
created() {
this.getSalesContent();
},
data: {
salesContent: '',
pageName: 'Sales',
salesNumber: '987-586-4511'
},
computed: {
htmlText() {
return `${this.salesContent}`;
//return this.salesContent;
}
},
methods: {
getSalesContent(){
axios.get('api/Sales').then(({ data }) => { // getting data from DB
this.salesContent = data.sales; //data.sales have this.pageName and this.salesNumber variables
});
}
}
});
Here is the example of data saved in db:
<p style="font-weight:bold"><span style="color:red">{{pageName}}</span>,</p>
<p style="font-weight:bold"><span style="color:red">${this.pageName} ${this.pageName}</span></p>
<p style="font-weight:bold">Contact Sales at ${this.salesNumber} {{salesNumber}}</span></p>
I used variables in all possible ways. But on the page they are printing in it the same way i saved it. Here is the output:
screenshot
Can anyone help me make it working.
Thanks in Advance.
According to the docs this does not seem possible:
https://v2.vuejs.org/v2/guide/syntax.html#Raw-HTML
Particularly:
The contents of the span will be replaced with the value of the
rawHtml property, interpreted as plain HTML - data bindings are
ignored.
You could as suggested in that answer just use a computed based on what you get from the server.
IMHO since the salesContent is fetched from db, it's a plain String. Thus nor vuejs or vanilla javascript will replace the inline variables with their values. (It may be possible by using eval, but it's totally out of question...) You should manually do that with String replace function. Like the following:
<p style="font-weight:bold"><span style="color:red">{{pageName}}</span>,</p>
<p style="font-weight:bold">Contact Sales at {{salesNumber}}</span></p>
methods: {
getSalesContent(){
axios.get('api/Sales').then(({ data }) => { // getting data from DB
let salesContent = data.sales; //data.sales have this.pageName and this.salesNumber variables
salesContent = salesContent.replace(/{{pageName}}/g, this.pageName)
salesContent = salesContent.replace(/{{salesNumber}}/g, this.salesNumber)
this.salesContent = salesContent
});
}
}

Puppeteer returns Arabic characters instead of English

I am using Puppeteer library to scrape some data from a web page but it returns sometimes weird characters. I have set already browser and page options like below. The weird part of that is not happening always. What could be the cause of that?
For example, I got this "چای خونه" instead of "Tea Room".
//I set these options for the headless browser
args: [
"--no-sandbox",
"--disable-notifications",
"--disable-dev-shm-usage",
"--lang=en-US,en-GB,en"
]
//I set also http 'Accept-Language' header like this way
await page.setExtraHTTPHeaders({
'Accept-Language': 'en-US'
});
// the function grabbing text from an html element
grabElementText(element) {
if (element) {
return element._page.evaluate(el => el.innerText, element);
}
}