Skip to content

Instantly share code, notes, and snippets.

@mariolopjr
Last active December 30, 2023 23:35
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mariolopjr/926875d4e7b6453378d2be5091cdfdbc to your computer and use it in GitHub Desktop.
Save mariolopjr/926875d4e7b6453378d2be5091cdfdbc to your computer and use it in GitHub Desktop.
Prism Script for Ghost
// License: MIT
Prism.plugins.autoloader.languages_path = 'https://cdnjs.cloudflare.com/ajax/libs/prism/1.9.0/components/';
Prism.plugins.autoloader.ignored_language = 'none'; // Update to allow arrays...
Prism.plugins.NormalizeWhitespace.setDefaults({
'remove-trailing': true,
'remove-indent': true,
'left-trim': true,
'right-trim': true,
});
var codes = $('code');
codes.addClass( 'line-numbers' );
$(document).ready(() => {
codes.each( ( i, el ) => {
var code = $( el );
var nonum = code.hasClass( 'language-nonum' );
const regex = /PS[a-zA-z]:\\/g;
if ( nonum ) {
code.children( 'span.line-numbers-rows' ).remove();
code.removeClass( 'language-nonum' );
// Construct classes
var codeClass = code.attr( 'class' );
var s = codeClass.substring(1, codeClass.length).split('-');
codeClass = 'language-' + s[0];
code.attr( 'class' , codeClass );
// Sets command line user if exists (enabled command line for code block)
var host = s.length >= 2 ? s[1] === 'l' ? 'localhost' : s[1] : 'none';
if ( host !== 'none' ) {
if ( host.match(regex) !== null ) {
code.parent().attr( { 'data-prompt': 'PS ' + host.slice(2) } );
} else {
code.parent().attr( { 'data-host': host } );
}
codeClass += ' command-line'
}
// Sets command line user (enabled command line for code block)
var user = s.length >= 3 ? s[2] === 'ps' ? 'none' : s[2] : 'none';
if ( user !== 'none' ) {
code.parent().attr( { 'data-user': user } );
}
// Set command line output lines if exists
var lines = '';
if ( s.length > 4 ) {
lines = s[3];
for (var i of s.slice(4)) {
lines += '-' + i;
}
}
else if ( s.length === 4 ) {
lines = s[3];
}
if ( s.length >= 4 ) {
code.parent().attr( { 'data-output': lines } );
}
code.parent().attr( 'class' , codeClass );
Prism.highlightElement(code[0]);
}
});
});
Prism.plugins.autoloader.languages_path='https://cdnjs.cloudflare.com/ajax/libs/prism/1.9.0/components/',Prism.plugins.autoloader.ignored_language='none',Prism.plugins.NormalizeWhitespace.setDefaults({'remove-trailing':!0,'remove-indent':!0,'left-trim':!0,'right-trim':!0});var codes=$('code');codes.addClass('line-numbers'),$(document).ready(()=>{codes.each((a,b)=>{var c=$(b),d=c.hasClass('language-nonum');const e=/PS[a-zA-z]:\\/g;if(d){c.children('span.line-numbers-rows').remove(),c.removeClass('language-nonum');var f=c.attr('class'),g=f.substring(1,f.length).split('-');f='language-'+g[0],c.attr('class',f);var h=2<=g.length?'l'===g[1]?'localhost':g[1]:'none';'none'!==h&&(null===h.match(e)?c.parent().attr({'data-host':h}):c.parent().attr({'data-prompt':'PS '+h.slice(2)}),f+=' command-line');var j=3<=g.length?'ps'===g[2]?'none':g[2]:'none';'none'!==j&&c.parent().attr({'data-user':j});var k='';if(4<g.length){k=g[3];for(var a of g.slice(4))k+='-'+a}else 4===g.length&&(k=g[3]);4<=g.length&&c.parent().attr({'data-output':k}),c.parent().attr('class',f),Prism.highlightElement(c[0])}})});
@kirvedx
Copy link

kirvedx commented Dec 19, 2023

For my use-case, I only wanted to be able to dictate nonum (or not), and/or specify command-line or powershell output using a markdown code-block, rather than having to use raw HTML. So the implementation I provide does only that - responding to nonum and additionally creating command-line or powershell output if also specified (requires nonum).

My implementation is based on self-hosting the components, so I downloaded the components to /var/www/<ghost-app>/versions/<ver>/themes/assets/components, and I symlinked components directly to assets/built/components. I drop this file, along with my basic prism.js into assets/js/lib and run npm run zip.

I did have to do an add_header directive (Content-Security-Policy spec) in my nginx configuration:

add_header Content-Security-Policy "script-src * 'self' 'unsafe-eval' 'unsafe-inline' blob: data:; script-src-elem * 'self' 'unsafe-eval' 'unsafe-inline' blob: data:" always;

Place it just inside of the location / {} directive. I tried other variations, but everything started working properly once I did this. I'd recommend getting specific and doing a granting list which properly specifies all sources, rather than blindly accepting every source like I did; It's only provided this way for insight.

The steps will be similar and can be adjusted for whatever theme you're using - in my case I'm using a custom source theme I've dubbed authoritative.

Notice (those of you borrowing) the use of rest spread, and null safety; Keep this in mind with regards to compatibility!

Thanks for the idea, the inspiration, and the effort - and more importantly for sharing it!

Top - Raw HTML, Bottom - Helper
Top (Raw HTML) Bottom (Helper)

Implementation for above
Implementation for Helper variant above

Log file, tail'd in command-line
Log file, tail'd in command-line

Implementation for tail'd log
Implementation for tail'd log

Helper doesn't break anything
Helper doesn't break anything

Clean console
Clean console

Content Security Policy
Content Security Policy

@mariolopjr
Copy link
Author

@kirvedx wow this is very detailed! Yes, feel free to use, modify, etc! I haven't used Ghost for years so this was a blast from the past!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment