Modify img tag in post's markdown using Jekyll Hooks - plugins

I have a Jekyll blog with 1,000s of posts. Now I'm planning to use Cloudflare Image Resizing to optimize the website. To make it happen I need to modify the image tag rendered from the markdown files.
In markdown file:
![Apple](images/apple.jpg)
Rendered image tag:
<img src="images/apple.jpg" alt="Apple">
How I want it to be:
<img src="/cdn-cgi/image/width=80,quality=75/images/apple.jpg" alt="Apple" >
Thanks in advance

The very last hook that gets called before writing posts to disk is :posts, :post_render. We can modify output at this hook to make edits to rendered posts and draft posts, regardless of whether they were originally written in Markdown or HTML:
module JekyllPluginHooks
Jekyll::Hooks.register(:posts, :post_render) do |post|
post.output.gsub!('<img src="images/', '<img src="/cdn-cgi/image/width=80,quality=75/images/')
end
end
Terminology
A Jekyll post includes drafts and blog posts.
A Jekyll document includes web pages in all collections, including drafts and blog posts.
A Jekyll page is a web page that does not belong to a collection, such as posts or drafts.
For Completeness
To modify all web pages in every collection, not just drafts and posts, use the :documents hook instead of the :posts hook in the above code example:
module JekyllPluginHooks
Jekyll::Hooks.register(:documents, :post_render) do |document|
document.output.gsub!('<img src="images/', '<img src="/cdn-cgi/image/width=80,quality=75/images/')
end
end
To also modify web pages that are not in a collection (for example, /index.html) also write:
module JekyllPluginHooks
Jekyll::Hooks.register(:pages, :post_render) do |page|
page.output.gsub!('<img src="images/', '<img src="/cdn-cgi/image/width=80,quality=75/images/')
end
end
If we want all web pages to be modified, we can rewrite the above and extract the common code to a new method called modify_output:
module JekyllPluginHooks
def modify_output
Proc.new do |webpage|
webpage.output.gsub! \
'<img src="images/', \
'<img src="/cdn-cgi/image/width=80,quality=75/images/'
end
end
module_function :modify_output
Jekyll::Hooks.register(:documents, :post_render, &modify_output)
Jekyll::Hooks.register(:pages, :post_render, &modify_output)
end
References
https://jekyllrb.com/docs/plugins/hooks/
https://www.mslinn.com/blog/2022/03/28/jekyll-plugin-template-collection.html

Related

How do I load an ejs template file into my HTML?

I am using EJS in the browser (not on the server).
I have some ejs that I would like to use in multiple pages, so I want to put that in its own file, say table.ejs.
Is there a way I can include it in my HTML such that it is immediately accessible to my javascript after onload?
I was thinking something like:
<script id="table-ejs" type="text/ejs" src="ejs/table.ejs"></script>
then in my javascript:
ejs.render(document.querySelector('#table-ejs').???, data)
Is this possible?
I could use the Fetch API to retrieve the ejs file but then I would need to rewrite a lot of code to make it async. I was wondering if I could avoid that.
Well,
place all your ejs-files within a file "views" - within your views you can create another file "partials" - in this file you place your header and footer.ejs.
Within, lets say, your home.ejs you have to include the following code:
<%- include('partials/header'); -%>
// the rest of your code
<%- include('partials/footer'); -%>
You can find more here: https://ejs.co/#docs

Creating two blogs on same website (Jekyll GitHub) without altering layout/formatting

I have recently tried creating a website using the Jekyll GitHub template here. One major alteration I hope to make to this template is to have two "blogs" in the format provided in the Blog tab of that template specifically shown here.
I (sort of) successfully created two blogs in my website and named the associated tabs (Media) and (Blog). I achieved this by reorganizing the file structure to have a "media" folder and a "blog" folder separately that each contain a _posts folder and index.html file. Now, when I add .md files in the _posts folder, these posts seem to get added to the correct tab (Media or Blog).
Even though that functionality works, both the Blog and Media tab lost their aesthetics compared to the style in the original template blog. Namely, 1) the banner image at the top is now gone; 2) the text formatting with the title in one line followed by the date in the "pretty" format (gray colored and in the format 29 Aug 2016) is now in a less-attractive bullet format with date first and in the format Aug 29, 2016; 3) the introductory excerpt text (in the example: "A pot still is a type of still used in distilling spirits such as whisky or brandy. Heat is applied directly to the pot containing the wash (for whisky) or wine (for brandy).") is now gone.
It is unclear to me why my separation of the _posts folder into two separate folders seems to cause these unwanted layout side effects. Since all three of these layout issues changed at once, I am assuming they can all be solved in the same solution. Whether or not that is true, any advice on how to solve these layout issues could be very helpful. Thank you for sharing any ideas!
You've removed the posts collection from your _config.yml which was setting the default feature_image for all posts. Unless you add that back in or include the overrides in each individual post it will not display the header (it may or may not also affect the rest of the styles):
collections:
media:
title: Media # Needed for Siteleaf
output: true
description: "Recent discussions with the media." # The post list page content
feature_text: |
Sharing our motivations and
opinions with the media.
feature_image: "https://picsum.photos/2560/600?image=866"
You're not actually using a media collection in either blog/index.html nor media/index.html, you're using the post.categories for filtering in the end, which will still causes some weird pagination once you start getting things rolling.
You may want to look at using the separate collections and then pre-building your site using paginator v2 (https://github.com/sverrirs/jekyll-paginate-v2/blob/master/README-GENERATOR.md) which will allow for pagination of different collections.
Edit 2020-01-23
Taking a new look at your repository, you still only have one (posts) collection. Therefore the logic for reading feature_* is being shared. If you look at the include site_feature.html you can see how the feature_image is being parsed out of the collections.
{% assign collectiondata = site.collections | where: "label", page.collectionpage | first %}
Which in your case is why Blog and Media both have the second image ?image=213. Your blog.html and media.html still have the front matter collectionpage: post.
I still think you're going down a slippery slope which will result in things not working exactly as you want them once you get more and more posts by doing it this way.

Typo3 Blog with Subtemplate

I am trying to set up the following structure:
Landing-Page (Root-Template)
--- Content Webpage 1
--- Content Webpage 2
------ Other Sub stuff
--- Blog (Blog-Template)
------ Blog stuff (apply Blog-Template)
--- 404, etc.
My problem with this is that if I am applying the blog template to my blog root, then my template is applied to all sites at the same level (so: Content Webpage 1 & 2, ...).
How can I prevent this and only assign my blog template to this site and lower?
P.S.: I am a beginner, so a bit of background would be nice if this is possible. I read a few of the Tutorials on docs.typo3.org, but that did not help...
You an create a template-record on the page Blog, then only that page and subpages get that configuration. Else the default configuration is taken which is or has to be defined in the root-template.
You also could use Conditions in the root-template to check for the Blog-Page and assign the special template inside that condition. Assumed your Blog has the pid (Page-Id) 5 the condition would look like this:
... (other stuff before)
[PIDinRootline = 5]
here you special template configuration
[global]
... (other stuff afterwards)
There is another option but there you need already advanced knowledge, as it's not explained too deep in my answer there (the TCA-part is missing): how to add multiple fluid-templates.
Okay, I finally got it to work like I desired.
Because the Blog-Template is a static Template I just assigend it to the main Template. Important was the order of the static Template includes.
Fluid styled content
Bootstrap package
Typo3 Blog
Typo3 Blog Template
The reason for that is that the Typo3 Blog Template needs the Fluid styled content and because my Fluid styled content include was the last one before, Typo3 threw me an error that it was not able to find some fluid elements.

How to generate Confluence page based on tabular data

I have some tabular data about users. I would like to have a Confluence page generated based on it. But I don't want to show the data as it is but instead have a nice table made of it.
For example data includes user identifier. But on the page I would like to have it used for few things. For example make an anchor to the user entry/row, show the identifier in a column and generate link (in another column) to some other tools where the identifier is an argument in URL.
This goes in obvious direction of data vs. presentation separation with all its benefits.
Now the problem is that I don't know how to do that while I feel that it should be somehow possible with all that Confluence offers.
There are various reporting macros. But the problem is how to get the initial tabular data. I tried using Excel (or CSV) attachment. But I failed to extract data from it (otherwise than just showing a simple table based on it).
Any advice? I'm using Confluence 5.4.
I have asked about it previously on Atlassian Answers in question Reporting on spreadsheet data from attachment but there are no answers so far and I think there will be none. While I think Stack Overflow is more popular so I hope that maybe here someone will have any advices.
For the 'display table information on the page' part: This could be achieved with a user macro. The CSV macro and HTML macro can be used to pull data in from an attachment or other locations to display on a wiki page.
There are other ways to display this kind of data. This be done with information extracted from a database using the SQL macro. Confluence can read in from its own database or from external databases.
For example, let's say you wanted to list all pages in a space with hyperlinks using the key page information to edit, view, delete the target page. The information being extracted in this example is in the Confluence table.
{sql-query:dataSource=wiki|output=wiki}
SELECT
'['||B.spacename||'|'||B.spacekey||':]' "Space Name",
'['||A.parentid ||'|///pages/viewpage.action?pageId='||A.parentid||']' "Page Parent",
'['||A.contentid||'|///pages/viewpage.action?pageId='||A.contentid||']' "Page Id",
'['||A.title ||'|///viewpage.action?pageId='||A.contentid||']' "Page Title",
'[View Page |///pages/viewpage.action?pageId='||A.contentid||']' "View Page",
'[Edit Page |///pages/editpage.action?pageId='||A.contentid||']' "Edit Page",
'[Delete Page |///pages/removepage.action?pageId='||A.contentid||']' "Delete Page"
FROM wiki.CONTENT A, SPACES B
WHERE B.SPACEKEY = 'sp' -- Put the spacekey here
AND B.SPACEID = A.SPACEID
AND A.TITLE like '%this%' -- Optionally, only return results for pages with the word 'this' in them
-- AND A.CONTENTID = 125999877 -- optionally, only return results for a single page by id
ORDER BY A.TITLE
{sql-query}
Once you have the content on the page it is possible to post-render wiki content using a JavaScript via the html macro.
{html}
<script type="text/javascript">
AJS.$(document).ready(function() {
AJS.$('#tableid').find('tr > td').contents().html('Hello world'); // or whatever to find and change the html or text
});
</script>
{html}
I presume your Confluence is version 4 or later. The default editor is WISIWYG, but you can also enable Source Editor (read Confluence doc on how to do this).
You can create source of a page in external editor and then copy/paste it in to Confluence Source Editor (or use Confluence REST API if you need to import multiple files).
Create a page with sample table, then view source of this page. Copy/paste elements of this page to your tabular data. Use search and replace patterns to insert tags in right places.
For example, if you have CSV file:
- replace commas with </th><th>
- put <tr><th> at the start of each line
- put </th><tr> at the end of each line
This should create nice table in Confluence.

Lazy load github gist files to display source code on the website

I have a couple of gists which I need to include in a website post to showcase the source code. Currently, I'm inlining each of the multiple gists at various places in the HTML with script tags, however, this would be a blocking call. So, is there a way to dynamically load the gists and paste it specific points in time.
I tried something like below :-
<html>
<body>
<div id="bookmarklet_1.js"></div>
<div id="bookmarklet_2.js"></div>
<div id="bookmarklet_3.js"></div>
var scriptMap = {'bookmarklet_1.js' : 'https://gist.github.com/892232.js?file=bookmarklet_1.js',
'bookmarklet_2.js' : 'https://gist.github.com/892234.js?file=bookmarklet_2.js',
'bookmarklet_3.js' : 'https://gist.github.com/892236.js?file=bookmarklet_3.js'};
var s, scr, holder;
for(s in scriptMap){
holder = document.getElementById(s);
scr= document.createElement('script');
scr.type= 'text/javascript';
scr.src= scriptMap[s];
holder.appendChild(scr);
}
</script>
</body>
</html>
The above didn't work for me, it seems that each script is doing a document.write internally to write the CSS and soure code. Has anyone tried this before or got it working ?
I started a project exactly for this purpose. Dynamically-embedded Gists
Try it now: http://urlspoiler.herokuapp.com/gists?id=992729
Use the above url as the src of a dynamically-created iframe, or add &format=html to get the Gist html snippet via ajax, then put it anywhere you want. (The gist in the above url also happens to be the documentation for how to use this project.)
I myself wanted to do exactly the same thing (with the addition of even removing the default gist style link) - ended up building a "generic" script loader that handles document.write calls :
https://github.com/kares/script.js
Here's how one can use it for embedding gists (and pasties) :
https://github.com/kares/script.js/blob/master/examples/gistsAndPasties.html
You can now get the HTML + CSS directly using JSONP.
I wrote a fuller answer in response to this question, but the key is that you can get the HTML + CSS using JSONP.
For example: https://gist.github.com/anonymous/5446989.json?callback=callback12345
callback12345({
"description": "Function to load a Gist without an iframe",
"public": true,
...
"div": <HTML code>,
"stylesheet": <URL of CSS file>
})