.each(function (key, value) { var langDiv = $(value); if (langDiv.length > 0) { var reallang = langDiv[0].className.replace(/hljs|wrap/g, '').trim(); var codeDiv = langDiv.find('.code'); var code = ""; if (codeDiv.length > 0) code = codeDiv.html(); else code = langDiv.html(); code = md.utils.unescapeAll(code); if (!reallang) { var result = { value: md.utils.escapeHtml(code) }; } else if (reallang == "tiddlywiki" || reallang == "mediawiki") { var result = { value: Prism.highlight(code, Prism.languages.wiki) }; } else { var languages = hljs.listLanguages(); if (languages.indexOf(reallang) == -1) { var result = hljs.highlightAuto(code); } else { var result = hljs.highlight(reallang, code); } } if (codeDiv.length > 0) codeDiv.html(result.value); else langDiv.html(result.value); } });
exports.language = function(language) { if (!language) { return null; } if (language === 'html') { return 'html'; } const shortcuts = { js: 'javascript', jsx: 'javascript', json: 'javascript', py: 'python', rb: 'ruby', md: 'markdown', mkd: 'markdown', 'c++': 'cpp', }; if (language && shortcuts[language]) { language = shortcuts[language]; } if (!language || hl.listLanguages().indexOf(language) < 0) { return null; } return language; };
const codeblocks = (message) => { // Count occurencies of ``` const count = (message.html.match(/```/g) || []).length; if (count) { // Check if we need to add a final ``` if ((count % 2) > 0) { message.html = `${ message.html }\n\`\`\``; message.msg = `${ message.msg }\n\`\`\``; } // Separate text in code blocks and non code blocks const msgParts = message.html.split(/(^.*)(```(?:[a-zA-Z]+)?(?:(?:.|\r|\n)*?)```)(.*\n?)$/gm); for (let index = 0; index < msgParts.length; index++) { // Verify if this part is code const part = msgParts[index]; const codeMatch = part.match(/^```(.*[\r\n\ ]?)([\s\S]*?)```+?$/); if (codeMatch != null) { // Process highlight if this part is code const singleLine = codeMatch[0].indexOf('\n') === -1; const lang = !singleLine && Array.from(hljs.listLanguages()).includes(s.trim(codeMatch[1])) ? s.trim(codeMatch[1]) : ''; const code = singleLine ? s.unescapeHTML(codeMatch[1]) : lang === '' ? s.unescapeHTML(codeMatch[1] + codeMatch[2]) : s.unescapeHTML(codeMatch[2]); const result = lang === '' ? hljs.highlightAuto((lang + code)) : hljs.highlight(lang, code); const token = `=!=${ Random.id() }=!=`; message.tokens.push({ highlight: true, token, text: `<pre><code class='code-colors hljs ${ result.language }'><span class='copyonly'>\`\`\`<br></span>${ result.value }<span class='copyonly'><br>\`\`\`</span></code></pre>`, noHtml: `\`\`\`\n${ s.stripTags(result.value) }\n\`\`\`` }); msgParts[index] = token; } else { msgParts[index] = part; } } // Re-mount message return message.html = msgParts.join(''); } };
controller.baseModel = function() { return { server: { uptime: process.uptime() }, site: { protocol: config("site.protocol", "http"), domain: config("site.domain", "localhost:8080"), pathPrefix: config("site.pathPrefix", ""), locale: config("site.locale", "en"), dateFormat: config("site.dateFormat", "MM/DD/YYYY hh:mm:ss"), timeOffset: config("site.timeOffset", 0), vkontakte: { integrationEnabled: !!config("site.vkontakte.integrationEnabled", false), appId: config("site.vkontakte.appId", "") }, twitter: { integrationEnabled: !!config("site.twitter.integrationEnabled", true) } }, styles: Tools.styles(), codeStyles: Tools.codeStyles(), availableCodeLangs: Highlight.listLanguages().map(function(lang) { return { id: lang, name: (langNames.hasOwnProperty(lang) ? langNames[lang] : lang) }; }), maxSearchQueryLength: config("site.maxSearchQueryLength", 50), markupModes: [ { name: "NONE", title: Tools.translate("No markup", "markupMode") }, { name: markup.MarkupModes.ExtendedWakabaMark, title: Tools.translate("Extended WakabaMark only", "markupMode") }, { name: markup.MarkupModes.BBCode, title: Tools.translate("bbCode only", "markupMode") }, { name: (markup.MarkupModes.ExtendedWakabaMark + "," + markup.MarkupModes.BBCode), title: Tools.translate("Extended WakabaMark and bbCode", "markupMode") }, ], supportedCaptchaEngines: Captcha.captchaIds().map(function(id) { return Captcha.captcha(id).info(); }) }; };
.each((key, value) => { const langDiv = $(value) if (langDiv.length > 0) { const reallang = langDiv[0].className.replace(/hljs|wrap/g, '').trim() const codeDiv = langDiv.find('.code') let code = '' if (codeDiv.length > 0) code = codeDiv.html() else code = langDiv.html() var result if (!reallang) { result = { value: code } } else if (reallang === 'haskell' || reallang === 'go' || reallang === 'typescript' || reallang === 'jsx' || reallang === 'gherkin') { code = unescapeHTML(code) result = { value: Prism.highlight(code, Prism.languages[reallang]) } } else if (reallang === 'tiddlywiki' || reallang === 'mediawiki') { code = unescapeHTML(code) result = { value: Prism.highlight(code, Prism.languages.wiki) } } else if (reallang === 'cmake') { code = unescapeHTML(code) result = { value: Prism.highlight(code, Prism.languages.makefile) } } else { code = unescapeHTML(code) const languages = hljs.listLanguages() if (!languages.includes(reallang)) { result = hljs.highlightAuto(code) } else { result = hljs.highlight(reallang, code) } } if (codeDiv.length > 0) codeDiv.html(result.value) else langDiv.html(result.value) } })
/** * get supported languages by highlight-js * @returns {Array<string>} - supported languages by highlight-js * @static */ static getHighlightJSLanguages() { return hljs.listLanguages(); }
grunt.registerMultiTask('mini_static_blog', 'Grunt plugin for creating a static blog', function() { // Import external libraries var Handlebars = require('handlebars'), Moment = require('moment'), RSS = require('rss'), hljs = require('highlight.js'), MarkedMetadata = require('meta-marked'), _ = require('lodash'), parseUrl = require('url'); // Declare variables var output, path; // Import options var options = this.options({ year: new Date().getFullYear(), size: 5 }); options.domain = parseUrl.parse(options.data.url).hostname; // Register partials Handlebars.registerPartial({ header: grunt.file.read(options.template.header), footer: grunt.file.read(options.template.footer) }); // Get languages var langs = hljs.listLanguages(); // Get Marked Metadata MarkedMetadata.setOptions({ gfm: true, tables: true, smartLists: true, smartypants: true, langPrefix: 'hljs lang-', highlight: function (code, lang) { if (typeof lang !== "undefined" && langs.indexOf(lang) > 0) { return hljs.highlight(lang, code).value; } else { return hljs.highlightAuto(code).value; } } }); // Get matching files var posts = grunt.file.expand(options.src.posts + '*.md', options.src.posts + '*.markdown'); var pages = grunt.file.expand(options.src.pages + '*.md', options.src.pages + '*.markdown'); // Get Handlebars templates var postTemplate = Handlebars.compile(grunt.file.read(options.template.post)); var pageTemplate = Handlebars.compile(grunt.file.read(options.template.page)); var indexTemplate = Handlebars.compile(grunt.file.read(options.template.index)); var notFoundTemplate = Handlebars.compile(grunt.file.read(options.template.notfound)); // Generate posts var post_items = []; posts.forEach(function (file) { // Convert it to Markdown var content = grunt.file.read(file); var md = new MarkedMetadata(content); var mdcontent = md.html; var meta = md.meta; // Get path var permalink = '/blog/' + (file.replace(options.src.posts, '').replace(/(\d{4})-(\d{2})-(\d{2})-/, '$1/$2/$3/').replace('.markdown', '').replace('.md', '')); var path = options.www.dest + permalink; // Render the Handlebars template with the content var data = { year: options.year, data: options.data, domain: options.domain, path: permalink + '/', meta: { title: meta.title.replace(/"/g, ''), date: meta.date, formattedDate: new Moment(new Date(meta.date)).format('Do MMMM YYYY h:mm a'), categories: meta.categories }, post: { content: mdcontent, rawcontent: content } }; post_items.push(data); }); // Sort posts post_items = _.sortBy(post_items, function (item) { return item.meta.date; }); // Get recent posts var recent_posts = post_items.slice(Math.max(post_items.length - 5, 1)).reverse(); // Output them post_items.forEach(function (data, index, list) { // Get next and previous if (index < (list.length - 1)) { data.next = { title: list[index + 1].meta.title, path: list[index + 1].path }; } if (index > 0) { data.prev = { title: list[index - 1].meta.title, path: list[index - 1].path }; } // Get recent posts data.recent_posts = recent_posts; // Render template var output = postTemplate(data); // Write post to destination grunt.file.mkdir(options.www.dest + data.path); grunt.file.write(options.www.dest + data.path + '/index.html', output); }); // Generate pages pages.forEach(function (file) { // Convert it to Markdown var content = grunt.file.read(file); var md = new MarkedMetadata(content); var mdcontent = md.html; var meta = md.meta; var permalink = '/' + (file.replace(options.src.pages, '').replace('.markdown', '').replace('.md', '')); var path = options.www.dest + permalink; // Render the Handlebars template with the content var data = { year: options.year, data: options.data, domain: options.domain, path: path, meta: { title: meta.title.replace(/"/g, ''), date: meta.date }, post: { content: mdcontent, rawcontent: content }, recent_posts: recent_posts }; var output = pageTemplate(data); // Write page to destination grunt.file.mkdir(path); grunt.file.write(path + '/index.html', output); }); // Generate RSS feed var feed = new RSS({ title: options.data.title, description: options.data.description, url: options.data.url }); // Get the posts for (var post in post_items.reverse().slice(0, 20)) { // Add to feed feed.item({ title: post_items[post].meta.title, description: post_items[post].post.content, url: options.data.url + post_items[post].path, date: post_items[post].meta.date }); } // Write the content to the file path = options.www.dest + '/atom.xml'; grunt.file.write(path, feed.xml({indent: true})); // Create 404 page var newObj = { data: options.data, year: options.year, domain: options.domain }; output = notFoundTemplate(newObj); path = options.www.dest; grunt.file.mkdir(path); grunt.file.write(path + '/404.html', output); // Generate index // First, break it into chunks var postChunks = []; while (post_items.length > 0) { postChunks.push(post_items.splice(0, options.size)); } // Then, loop through each chunk and write the content to the file for (var chunk in postChunks) { var data = { year: options.year, data: options.data, domain: options.domain, posts: [] }; // Get the posts for (post in postChunks[chunk]) { data.posts.push(postChunks[chunk][post]); } // Generate content if (Number(chunk) + 1 < postChunks.length) { data.nextChunk = Number(chunk) + 2; } if (Number(chunk) + 1 > 1) { data.prevChunk = Number(chunk); } data.recent_posts = recent_posts; output = indexTemplate(data); // If this is the first page, also write it as the index if (chunk === "0") { grunt.file.write(options.www.dest + '/index.html', output); } // Write the content to the file path = options.www.dest + '/posts/' + (Number(chunk) + 1); grunt.file.mkdir(path); grunt.file.write(path + '/index.html', output); } });
grunt.registerMultiTask('mini_static_blog', 'The best Grunt plugin ever.', function() { // Import external libraries var Handlebars = require('handlebars'), Moment = require('moment'), RSS = require('rss'), hljs = require('highlight.js'), MarkedMetadata = require('meta-marked'), _ = require('lodash'), parseUrl = require('url'); // Declare variables var output, path; // Import options var options = this.options({ year: new Date().getFullYear(), size: 5 }); options.domain = parseUrl.parse(options.data.url).hostname; // Register partials Handlebars.registerPartial({ header: grunt.file.read(options.template.header), footer: grunt.file.read(options.template.footer) }); // Get languages var langs = hljs.listLanguages(); // Get Marked Metadata MarkedMetadata.setOptions({ gfm: true, tables: true, smartLists: true, smartypants: true, langPrefix: 'hljs lang-', highlight: function (code, lang) { if (typeof lang !== "undefined" && langs.indexOf(lang) > 0) { return hljs.highlight(lang, code).value; } else { return hljs.highlightAuto(code).value; } } }); // Get matching files var posts = grunt.file.expand(options.src.posts + '*.md', options.src.posts + '*.markdown'); var pages = grunt.file.expand(options.src.pages + '*.md', options.src.pages + '*.markdown'); // Get Handlebars templates var postTemplate = Handlebars.compile(grunt.file.read(options.template.post)); var pageTemplate = Handlebars.compile(grunt.file.read(options.template.page)); var indexTemplate = Handlebars.compile(grunt.file.read(options.template.index)); var notFoundTemplate = Handlebars.compile(grunt.file.read(options.template.notfound)); // Generate posts var post_items = []; posts.forEach(function(file) { // Convert it to Markdown var content = grunt.file.read(file); var md = new MarkedMetadata(content); var mdcontent = md.html; var meta = md.meta; // Get path var permalink = '/blog/' + (file.replace(options.src.posts, '').replace(/(\d{4})-(\d{2})-(\d{2})-/, '$1/$2/$3').replace('.markdown', '').replace('.md', '')); var path = options.www.dest + permalink; // Render the Handlebars template with the content var data = { year: options.year, data: options.data, domain: options.domain, path: permalink + '/', meta: { title: meta.title.replace(/"/g, ''), date: meta.date, formattedDate: new Moment(new Date(meta.date)).format('Do MMMM YYYY h:mm a'), categories: meta.categories }, post: { content: mdcontent, rawcontent: content } }; post_items.push(data); }); // Sort posts post_items = _.sortBy(post_items, function(item) { return item.meta.date; }); // Get recent posts var recent_posts = post_items.slice(Math.max(post_items.length - 5, 1)).reverse(); // Output them post_items.forEach(function(data, index, list) { // Get next and previous if (index < (list.length - 1)) { data.next = { title: list[index + 1].meta.title, path: list[index + 1].path }; } // Get recent posts data.recent_posts = recent_posts; // Render template var output = postTemplate(data); // Write post to destination grunt.file.mkdir(options.www.dest + data.path); grunt.file.write(options.www.dest + data.path + '/index.html', output); }); /* Merge task-specific and/or target-specific options with these defaults. var options = this.options({ punctuation: '.', separator: ', ' }); */ // Iterate over all specified file groups. this.files.forEach(function(f) { // Concat specified files. var src = f.src.filter(function(filepath) { // Warn on and remove invalid source files (if nonull was set). if (!grunt.file.exists(filepath)) { grunt.log.warn('Source file "' + filepath + '" not found.'); return false; } else { return true; } }).map(function(filepath) { // Read file source. return grunt.file.read(filepath); }).join(grunt.util.normalizelf(options.separator)); // Handle options. src += options.punctuation; // Write the destination file. grunt.file.write(f.dest, src); // Print a success message. grunt.log.writeln('File "' + f.dest + '" created.'); }); });