diff --git a/.gitignore b/.gitignore index 9bb63229ff531347d03e5e256210d6f2065f61dd..36bea9ee70a3ad1bbaa79dd00cedcdefe380b831 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ build build-debug content static +.buildconfig diff --git a/index.js b/index.js index fa36619b60748a2cdb04125932eb4b75e97d38db..243f658518836c063f02bf6a8d1bc4de712af310 100755 --- a/index.js +++ b/index.js @@ -1,178 +1,136 @@ #!/usr/bin/env node -var sitegin = require('./sitegin/sitegin'); - -var input = new sitegin.input.Hugo(process.cwd()+'/content/'); -var transformerMD = new sitegin.transformer.Markdown; -var transformerTags = new sitegin.transformer.Tags; -var transformerNunjucks = new sitegin.transformer.Nunjucks; -var transformerUrlizeTags = new sitegin.transformer.UrlizeTags; -var output = new sitegin.output.Filesystem; -var sequencer = new sitegin.Sequencer; -var transformerGit = new sitegin.transformer.Git; -var transformerOther = new sitegin.transformer.Other; -var transformerImages = new sitegin.transformer.Images; - -var sass = require('node-sass'); -var fs = require('fs'); - -var builddir = "build"; -if(process.argv[2] !== "compileonly") builddir = "build-debug"; - -var oldEmit = sequencer.emit; -sequencer.emit = function() { - console.log("Event:",arguments[0]); - oldEmit.apply(sequencer, arguments); -} +var moment = require('moment'); +var cli = require('cli'); +var config = require('./sitegin/config'); + +cli.main(function(args, options) { + console.log(options); + config() + .then(function(obj) { + sitegin(obj.config); + }) + .catch(function(e) { + console.log(e.stack); + process.exit(); + }); +}); -sequencer.on("", function(ev) { - console.log("Event:",ev); -}) +var sitegin = function(config) { + var options = config.options; + require('./sitegin/sitegin')({ + watch: !options.noserver + }) + .then(function onLoad(jobs) { + var sass = require('node-sass'); + var fs = require('fs'); + + // Main builder function + // If builder is not running - run it + // If it is running - schedule rerun after it finishes + var isRunning = false; + var runAgain = false; + var doSync = function(){} + function run() { + var startTime = moment(); + runAgain = false; + if(isRunning) { + console.log("Generator is still running. Queing another run after it finishes.") + runAgain = true; + return; + } + console.log("================================================================================") + console.log("Running generator") + isRunning = true; + jobs.run('pipeline',jobs) + .then(function() { + isRunning = false; + console.log("Generator finished in",moment().diff(startTime,'seconds'),'seconds') + doSync(); + if(runAgain) run(); + }) + .catch(function(e) { + isRunning = false; + console.log("Generator crashed in",moment().diff(startTime,'seconds'),'seconds') + if(runAgain) run(); + if(e.stack) + console.log(e.stack) + else + console.log(e) + }); + } -var tasks = []; -var onDone = function(what) { - console.log(what, 'done'); - var removed = false; - for(var i = 0; i < tasks.length; i++) { - if(tasks[i] == what) { - removed = true; - tasks.splice(i,1); - break; + console.log('Sitegin successfully loaded'); + run(); + copyStaticFiles(config.builddir); + rendersass(config.builddir); + + if(!options.noserver) { + var sync = require('browser-sync').create(); + doSync = function() { + sync.reload('*') + } + sync.init({ + server: { + baseDir: config.builddir + }, + ui: { + port: options.port+1 + }, + port: options.port + }); + + var chokidar = require('chokidar'); + // article or theme reload + chokidar.watch(['content/','theme/'], {ignoreInitial: true}) + .on('all', function(event, path) { + console.log('Content or theme changed. Rebuilding...'); + run(); + }) + + // sitegin reload + jobs.onReload(function() { + console.log("Sitegin reloaded"); + run(); + }) } - } - if(!removed && process.argv[2] == "compileonly") throw new Error("Task "+what+" ended but was never registered"); - if(tasks.length == 0 && process.argv[2] == "compileonly") { - console.log("exitting"); + }) + .catch(function(e) { + console.log(e.stack); process.exit(); - } + }); } +var copyStaticFiles = function(builddir) { + // STATIC FILES + var fsextra = require('node-fs-extra'); + fsextra.copy( + 'static', + builddir, + function(file){ return !(file.match(".git") || file.match("static/articles")); }, + function(){console.log("copy static done");} + ); + fsextra.copy( + 'static/articles', + builddir+"/clanek", + function(){console.log("copy static/articles done");} + ); + fsextra.copy( + 'theme/static', + builddir, + function(file){ return !file.match("\\.git") }, + function(){console.log("copy theme/static done");} + ); +} -// PIPELINE -sequencer -.load(input) -.registerNext(transformerGit) -.registerNext(transformerOther) -.registerNext(transformerImages) -.registerNext(transformerMD) -.registerNext(transformerUrlizeTags) -.registerNext(transformerTags) -.registerNext(transformerNunjucks) -.registerNext(output) -.finish(function(list) { - onDone("sequencer"); -}) -tasks.push('sequencer'); - -try {fs.mkdirSync(builddir);}catch(e){} -try {fs.mkdirSync(builddir+"/theme");}catch(e){} +var rendersass = function(builddir) { + // SASS + var sass = require('node-sass'); + var fs = require('fs'); -// SASS -var rendersass = function() { sass.render ({file: "theme/sass/style.scss"},function(err, result) { if(err == null) { console.log("compiled sass"); fs.writeFile(builddir+"/theme/style.css",result.css); } else console.log("error ", err); - onDone("sass"); }); }; -tasks.push('sass'); - -rendersass(); - -// STATIC FILES -var fsextra = require('node-fs-extra'); -tasks.push('copy static'); -fsextra.copy( - 'static', - builddir, - function(file){ return !(file.match(".git") || file.match("static/articles")); }, - function(){onDone("copy static");} - ); -tasks.push('copy static/articles'); -fsextra.copy( - 'static/articles', - builddir+"/clanek", - function(){onDone("copy static/articles");} - ); -tasks.push('copy theme static'); -fsextra.copy( - 'theme/static', - builddir, - function(file){ return !file.match("\\.git") }, - function(){onDone("copy theme static");} - ); - -// DEVEL INCOMING -if(process.argv[2] !== "compileonly") { - var sync = require('browser-sync').create(); - sync.init({ - server: { - baseDir: builddir - }, - ui: { - port: 1338 - }, - port: 1337 - }); - - // CHANGE WATCHER - var chokidar = require('chokidar'); - - chokidar.watch('theme/static', {ignoreInitial: true, usePolling: false}) - .on('all', (event, path) => { - console.log(path); - console.log("theme static copy watcher"); - fsextra.copy( - 'theme/static', - builddir, - function(file){ return !file.match(".git"); }, - function(){} - ); - sync.reload(path); - }); - - chokidar.watch('static/', {ignoreInitial: true, usePolling: false}) - .on('all', (event, path) => { - if(path.match(/^static\/articles\/.*$/)) return; - console.log("static copy watcher"); - fsextra.copy( - 'static', - builddir, - function(file){ return !(file.match(".git") || file.match("static/articles")); }, - function(){} - ); - sync.reload(path); - }) - .unwatch('static/articles'); - - chokidar.watch('static/articles', {ignoreInitial: true, usePolling: false}) - .on('all', (event, path) => { - console.log("static articles copy watcher"); - fsextra.copy('static/articles',builddir+"/clanek",function(){}); - sync.reload(path); - }) - .unwatch('static/articles'); - - chokidar.watch(['theme/','content/'], {ignoreInitial: true, usePolling: false}) - .on('all', (event, path) => { - if(path.match(/^theme\/static\/.*$/)) return; - if(path.match(/^theme\/sass\/.*$/)) return; - console.log("rebuild watcher",path); - sequencer.load(input); - }) - .unwatch("theme/static") - .unwatch("theme/sass"); - - sequencer.finish(function() { - sync.reload("*.html"); - }); - - chokidar.watch('theme/sass', {ignoreInitial: true, usePolling: false}) - .on('all', function(event, path) { - console.log("sass: file change detected - rerendering "+event+" "+path); - rendersass(); - sync.reload(path); - }); -} - diff --git a/package.json b/package.json index 73a647931908bd034f1dc71f593d0610eac6be94..5be70aa4c762322f93b7460ed097acc2bef0c80f 100644 --- a/package.json +++ b/package.json @@ -7,11 +7,13 @@ "test": "./node_modules/istanbul/lib/cli.js cover ./node_modules/mocha/bin/_mocha -- sitegin/test/ --recursive -R spec -u exports -t 60000" }, "author": "", - "license": "BSD", + "license": "UNSPECIFIED", "dependencies": { "browser-sync": "^2.11.1", "chokidar": "^1.4.3", + "cli": "^0.11.2", "highlight.js": "^9.2.0", + "jsesc": "^1.0.0", "marked": "^0.3.5", "mkdirp": "^0.5.1", "moment": "^2.12.0", @@ -21,8 +23,10 @@ "nodegit-kit": "^0.8.1", "nunjucks": "^2.3.0", "nunjucks-date-filter": "^0.1.1", + "syntax-error": "^1.1.5", "toml": "^2.3.0", - "toml-js": "0.0.8" + "toml-js": "0.0.8", + "walk": "^2.3.9" }, "devDependencies": { "istanbul": "^0.4.2", diff --git a/sitegin/Page.js b/sitegin/Page.js deleted file mode 100644 index 42e3f2899cf78586237a1ac5f09764db29927319..0000000000000000000000000000000000000000 --- a/sitegin/Page.js +++ /dev/null @@ -1,52 +0,0 @@ - -exports.Page = function() { - this.file = ""; - this.metadata = {}; - this.content = ""; - this.type = "article"; -} - -exports.PageList = function() { - var list = this; - list.list = []; - - list.length = 0; - - list.addPage = function(article) { - list.length++; - if(! (article instanceof exports.Page)) - throw "article has to be of type Page"; - else if(list.containsFile(article.file)) { - console.log(list.getPageByFile(article.file)); - throw "article is already in this list" - } else - list.list.push(article); - } - - list.forEach = function(f) { - list.list.forEach(f); - } - - list.getPageByFile = function(file) { - var rarticle = undefined; - list.forEach(function(article) { - if(article.file == file) { - rarticle = article; - } - }); - return rarticle; - } - - list.containsFile = function(file) { - var contains = false; - list.forEach(function(article) { - if(article.file == file) { - contains = true; - } - }); - return contains; - } - - return list; -} - diff --git a/sitegin/config.js b/sitegin/config.js new file mode 100644 index 0000000000000000000000000000000000000000..02378ba8a51e34e13d4f5a859f22f01aa778ccfc --- /dev/null +++ b/sitegin/config.js @@ -0,0 +1,33 @@ +/* + * This file specifies whole configuration of sitegin. + * In future it might actually read configuration files but for now - if you + * want to configure sitegin you have to modify this file. + * (or write config reader which would replace this file - I'd appreciate + * merge request for this feature ;) ) + */ +var cli = require('cli'); +var options = cli.parse({ + noserver: ['n', 'Dont run server'], + port: ['p', 'Port on which server should run', 'number', 1337], + uiport: [null, 'BrowserSync UI port', 'number', 'port+1'] +}); + +module.exports = function() { + var builddir = "build"; + if(!options.noserver) builddir = "build-debug"; + + if(options.uiport == 'port+1') { + options.uiport = options.port+1; + } + + return Promise.resolve({ + config: { + options: options, + builddir: builddir, + sourceDir: 'content', + articlesLocation: 'articles', + linksPerPage: 6 + } + }) +} +module.exports.watch = !options.noserver; diff --git a/sitegin/transformer-git.js b/sitegin/gitInfo.js similarity index 53% rename from sitegin/transformer-git.js rename to sitegin/gitInfo.js index bb0dc377cde042a26bb8fe8754956016518e21f2..076fce51bd1856db1d422c97d85eafef7b0d4fa6 100644 --- a/sitegin/transformer-git.js +++ b/sitegin/gitInfo.js @@ -1,4 +1,8 @@ -// Add git commit author and date to metadata +/* + * Add date: {creation, modification, modified} and author: {name, email} + * to metadata if not already present + */ + var nodegit = require('nodegit'); var git = require('nodegit-kit'); var path = require('path'); @@ -73,51 +77,38 @@ var getFilesHistory = function() { }); } -module.exports = function() { - var tr = this; - tr.fancyname = "transformer git"; - - tr.pre = function(cb, articleList) { - getFilesHistory() - .then((filesHistory) => { - var todo = articleList.length; - articleList.forEach(function(article) { - var file = path.relative(pathToRepo, article.origFile); - var commits = filesHistory[file]; - if(commits !== undefined) { - commits.sort(function(a,b){ - return b.date - a.date; - }); - var newestCommit = commits[0]; - var oldestCommit = commits[commits.length-1]; +module.exports = function(obj) { + return getFilesHistory() + .then((filesHistory) => { + obj.pages.forEach(function(article) { + var file = path.relative(pathToRepo, article.filename); + var commits = filesHistory[file]; + if(commits !== undefined) { + commits.sort(function(a,b){ + return b.date - a.date; + }); + var newestCommit = commits[0]; + var oldestCommit = commits[commits.length-1]; - if(article.metadata.date == undefined) - article.metadata.date = {}; + if(article.metadata.date == undefined) + article.metadata.date = {}; - if(article.metadata.date.creation == undefined) - article.metadata.date.creation = oldestCommit.date; + if(article.metadata.date.creation == undefined) + article.metadata.date.creation = oldestCommit.date; - article.metadata.date.modification = newestCommit.date; - article.metadata.date.modified = (newestCommit !== oldestCommit); + article.metadata.date.modification = newestCommit.date; + article.metadata.date.modified = (newestCommit !== oldestCommit); - if(article.metadata.author === undefined) - article.metadata.author = {} - if(article.metadata.author.name == undefined) - article.metadata.author.name = oldestCommit.author.name - if(article.metadata.author.email == undefined) - article.metadata.author.email = oldestCommit.author.email + if(article.metadata.author === undefined) + article.metadata.author = {} + if(article.metadata.author.name == undefined) + article.metadata.author.name = oldestCommit.author.name + if(article.metadata.author.email == undefined) + article.metadata.author.email = oldestCommit.author.email - article.commits = commits; - } - - todo--; - if(todo == 0) cb(); - }); - }) - .catch(function(err) {console.log(err.stack);}); - } - - tr.forEachPage = function(article, cb) { - cb(); - } + article.commits = commits; + } + }); + return obj; + }) } diff --git a/sitegin/input-hugo.js b/sitegin/input-hugo.js deleted file mode 100644 index a1725dcd23570e2c08084c28d87634b26a62e0b3..0000000000000000000000000000000000000000 --- a/sitegin/input-hugo.js +++ /dev/null @@ -1,130 +0,0 @@ -var fs = require('fs'); -var toml = require('toml'); -var PageList = require('./Page').PageList; -var Page = require('./Page').Page; -var moment = require('moment'); -var path = require('path'); - -function walk(currentDirPath, callback, end_cb) { - var subcalls = 0; - var ender = function() { - subcalls--; - if(subcalls <= 0) { - if(end_cb !== undefined) - end_cb(); - } - } - var fs = require('fs'), path = require('path'); - fs.readdir(currentDirPath, function(err, files) { - if(err!=null) console.log(err); - files.forEach(function(name) { - var filePath = path.join(currentDirPath, name); - try { - var stat = fs.statSync(filePath); - if (stat.isFile()) { - callback(filePath, stat); - } else if (stat.isDirectory()) { - if(filePath.indexOf(".git") < 0) { - subcalls++; - walk(filePath, callback, ender); - } - } - } catch(e) {} - }); - if(subcalls == 0) ender(); - - }); -}; - -var readPageWorker = function(file, articleName, contentDir) { - if(file === undefined) throw new Error("file is undefined"); - file = file.substring(4); - var fm_end = file.indexOf("+++"); - var obj = new Page; - obj.origFile = contentDir+articleName+'.md'; - obj.file = articleName.replace("articles","clanek"); - obj.content = file.substring(fm_end+4); - try { - obj.metadata = toml.parse(file.substring(0,fm_end-1)+"\n"); - } catch(e) { - console.log(articleName+": Failed to parse metadata"); - throw e; - } - if(obj.metadata.date && obj.metadata.date.creation) obj.metadata.date.creation = moment(obj.metadata.date.creation); - return obj; -} -module.exports = function(_contentDir) { - var exports = this; - exports.walk = walk; - exports.fancyname = "loader hugo"; - var contentDir = _contentDir; - if(contentDir == undefined) contentDir = './content/'; - if(!contentDir.endsWith('/')) contentDir+='/'; - - /* - * articleName: - * string - * callback: - * called when article is read - * returns: - * { - * string articleName,content - * object frontmatter - * function save - * } - */ - exports.readPage = function(articleName, cb) { - fs.readFile(contentDir+articleName+".md", 'utf8', function(err, data) { - if(err != null) throw err; - cb(readPageWorker(data, articleName, contentDir)); - }); - } - - /* - * callback: - * function(articleName) - * called for each article on website - * cb_end: - * function() - * called when all articles are listed - */ - exports.forEachPage = function(callback, cb_end) { - walk(contentDir+"articles",function(filePath, stat) { - console.log(filePath, path.basename(filePath)); - if(path.basename(filePath).substr(0,1) == ".") return; - if(callback !== undefined) callback(filePath.substring(contentDir.length,filePath.length-3)); - }, function() { - if(cb_end !== undefined) cb_end(); - }); - }; - - /* - * cb: - * function(articleList) - * called after all cb_on_each - */ - exports.getPageList = function(cb) { - var currentlyReadingCount = 0; - var allPagesListed = false; - var cb_called = false; - var list = new PageList; - - exports.forEachPage(function(articleName) { - currentlyReadingCount++; - exports.readPage(articleName, function(article){ - list.addPage(article); - currentlyReadingCount--; - if(allPagesListed && currentlyReadingCount == 0 && !cb_called) { - if(cb !== undefined) cb(list); - cb_called = true; - } - }); - },function(){ - if(currentlyReadingCount == 0 && !cb_called) { - if(cb !== undefined) cb(list); - cb_called = true; - } - allPagesListed = true; - }); - }; -} diff --git a/sitegin/jobs.js b/sitegin/jobs.js new file mode 100644 index 0000000000000000000000000000000000000000..bf4ed3e409398a7f185c5fbbc1bfbb6d058115e0 --- /dev/null +++ b/sitegin/jobs.js @@ -0,0 +1,156 @@ +var syntaxError = require('syntax-error'); +var fs = require('fs'); +var chokidar = require('chokidar'); +var eventEmitter = new (require('events').EventEmitter); + +var jobList = {}; +var watchers = []; + +function JobError(message, name) { + Error.captureStackTrace(this, JobError); + this.name = name+'Error'; + this.message = message; + return this; +} + +var onReload = function() {} +var requireError = function(e, jobName, module, reject) { + if(e instanceof SyntaxError) { + var resolved = require.resolve(module); + fs.readFile(resolved, 'utf8', function(err, content) { + console.log(syntaxError(content,resolved)); + reject(new JobError('Failed to register job '+jobName,'Require')) + }) + } else { + if(e.code === 'MODULE_NOT_FOUND') + console.log(e.toString()); + reject(new JobError('Failed to register job '+jobName,'Require')) + } +} + +var jobs = { + register: function(jobName, module, watch) { + return new Promise(function(resolve, reject) { + if(watch === undefined) watch = true; + if(jobList[jobName] !== undefined) { + return Promise.reject( + new JobError('Job '+jobName+' is already registered', 'JobAlreadyRegistered') + ) + } + + var f; + try { + f = require(module); + } catch(e) { + requireError(e, jobName, module, reject); + return; + } + + if(typeof f !== 'function') + throw new JobError('Module "'+module+'" for job "'+jobName+'" does not export function'); + jobList[jobName] = { + f: f, + module: module + }; + if(watch) jobs.watch(jobName); + resolve(); + + }); + }, + reload: function(jobName) { + var module = jobList[jobName].module; + delete require.cache[require.resolve(module)]; + + return new Promise(function(resolve, reject) { + try { + var f = require(module); + if(typeof f === 'function') { + var job = { + f: f, + module: module + }; + delete jobList[jobName]; + jobList[jobName] = job; + resolve(); + } else { + console.log('Error reloading job '+jobName+' retry in 500ms'); + setTimeout(function() { + resolve(jobs.reload(jobName)) + },500) + } + } catch(e) { + console.log(e); + requireError(e, jobName, module, reject); + } + }); + }, + // registerMultiple( + // {watch: true}, + // ['jobName','./module'],['jobName2','./module2'] + // ) + registerMultiple: function() { + var regs = []; + var watch = true; + for(i in arguments) { + var job = arguments[i]; + if(i == 0) { + if(job.watch !== undefined) watch = job.watch; + } else { + regs.push(jobs.register(job[0], job[1], watch)); + } + } + return Promise.all(regs); + }, + run: function() { + var jobName = arguments[0]; + if(jobList[jobName] === undefined) { + throw new JobError('Job '+jobName+' is not registered', 'JobNotRegistered') + } + try { + return jobList[jobName].f.apply(null, Array.prototype.slice.call(arguments, 1)); + } catch(e) { + console.log("Error running job",jobName); + console.log(jobList[jobName]); + throw e; + } + }, + runSequence: function() { + var prom; + console.log("Running",Array.prototype.slice.call(arguments, 0)) + var jobSequence = [].splice.call(arguments, 0); + jobSequence.forEach(function(job){ + if(prom === undefined) { + prom = jobs.run(job); + } else { + prom = prom.then(function() { + var args = [].splice.call(arguments, 0); + args.splice(0,0,job); + return jobs.run.apply(null,args) + }) + } + }); + return prom; + }, + watch: function(jobName) { + var module = jobList[jobName].module; + var file = require.resolve(module); + var w = chokidar.watch(file); + w.on('change', path => { + jobs.reload(jobName) + .then(onReload); + }); + watchers.push(w); + }, + onReload: function(f) { + onReload = f; + }, + close: function() { + watchers.forEach(function(w) { + w.close(); + console.log(w.getWatched()); + }); + watchers = []; + } +} + +module.exports = jobs; diff --git a/sitegin/transformer-markdown.js b/sitegin/markdown.js similarity index 61% rename from sitegin/transformer-markdown.js rename to sitegin/markdown.js index e6bb54040ec45cb1ab64170433f9751cd8354ecc..81b2bd272680d24a5271084680d13d2407ce2f41 100644 --- a/sitegin/transformer-markdown.js +++ b/sitegin/markdown.js @@ -1,22 +1,21 @@ +/* + * Transforms pages[0..length].content from markdown to HTML + */ + var marked = require('marked'); var renderer = new marked.Renderer(); -var toURL = require('./transformer-urlizetags.js').toURL; var highlightjs = require('highlight.js'); var path = require('path'); -var minificationOK = true; -try {require('lwip');} -catch(e) { - minificationOK = false; -} -if(process.argv[2] !== "compileonly") minificationOK = false; +var jobs = require('./jobs'); -var images = {}; +var toURL = function(url) { + return jobs.run('toURL', url); +} renderer.heading = function(text, level, raw) { return '<h' + (level+2) + ' id="' - + this.options.headerPrefix + toURL(raw) + '">' + text @@ -41,41 +40,14 @@ marked.setOptions({ smartypants: false, }); -module.exports = function() { - var tr = this; - tr.fancyname = "transformer markdown"; - tr.pre = function(cb, list) { - if(minificationOK) { - list.images.forEach((img) => { - images[img.file] = img; - }); - } - cb(); - }; - tr.forEachPage = function(article, cb) { - article.origContent = article.content; +module.exports = function(obj) { + obj.pages.forEach(function(article) { renderer.image = function(href, title, text) { href = href.split(path.sep).join("/"); href = href.split(" ="); var size = href[1]; href = href[0]; - var rel = path.relative(process.cwd(),path.resolve(article.file,href)); - rel = rel.split(path.sep).join("/"); - var img = images[rel]; - var full; - if(img) { - if(img.minified) { - full = href; - href = path.relative(article.file, img.thumb); - }else if(!minificationOK) { - full = href; - } - } - else if(process.argv[3] !== "final") { - if(!href.match("://")) { - href = "https://ok1kvk.cz"+href; - } - } + var rel = path.relative(process.cwd(),path.resolve(article.filename,href)); var out = '<img src="' + href + '" alt="' + text + '"'; if(size !== undefined) { @@ -86,15 +58,14 @@ module.exports = function() { if(size.length > 1 && size[1].length > 0) { out += ' height="' + size[1] + '"'; } - } else if(!minificationOK) { - out += ' style="max-width:512px"'; } if (title) { out += ' title="' + title + '"'; } - + out += '>'; - if(full) { + if(true) { // if lightbox + var full = href; var a = '<a href="'+full+'"'; a += ' data-lightbox="group"'; a += ' data-title="' + text + '"'; @@ -116,6 +87,6 @@ module.exports = function() { }, renderer: renderer }); - cb(); - } + }); + return Promise.resolve(obj); } diff --git a/sitegin/nunjucks.js b/sitegin/nunjucks.js new file mode 100644 index 0000000000000000000000000000000000000000..aa87c04145ec7fa8971ff4ebf5fdfde20ca9ca46 --- /dev/null +++ b/sitegin/nunjucks.js @@ -0,0 +1,57 @@ +/* + * This job renders `data` using nunjucks template `type` + */ + +var nunjucks = require('nunjucks'); +var fs = require('fs'); +var dateFilter = require('nunjucks-date-filter'); +var util = require('util'); + +var watch = require('./config').watch; +console.log('watch: '+watch); +var env = new nunjucks.Environment( + new nunjucks.FileSystemLoader('theme/templates',{watch: watch}) +); + +env.addFilter('date', dateFilter); + +env.addFilter('paginationList', function(page, count) { + var curPage = page; + var pages = []; + pages.push(curPage); + for(var i = 0; i < count; i++) { + curPage = curPage.metadata.prevpage; + if(curPage === undefined) break; + pages.unshift(curPage); + } + + curPage = page; + for(var i = 0; i < count; i++) { + curPage = curPage.metadata.nextpage; + if(curPage === undefined) break; + pages.push(curPage); + } + return pages; +}); + +env.addFilter('inspect', function(obj) { + return util.inspect(obj); +}); + +env.addFilter('relURL', function(filename, dir){ + if(filename.substr(0,1) == '/' || filename.match('://')) return filename; + if(dir.substr(0,1) !== '/') dir = '/' + dir; + if(filename.match(/\/$/)) return dir+filename; + return dir+'/'+filename; +}) + +module.exports = function(data, type) { + return new Promise(function(resolve, reject) { + env.getTemplate(type+'.html.nunj', true, function(err, tmpl) { + if(err) reject(new Error('Failed to load template '+type+'.html.nunj')); + resolve(tmpl); + }); + }).then(function(tmpl) { + return tmpl.render(data); + }); +} diff --git a/sitegin/output-console.js b/sitegin/output-console.js deleted file mode 100644 index b9074e197f3a216af4ce99d5c0802e9af2b648b3..0000000000000000000000000000000000000000 --- a/sitegin/output-console.js +++ /dev/null @@ -1,9 +0,0 @@ - -module.exports = function() { - var out = this; - out.fancyname = "output console"; - out.forEachPage = function(article, cb) { - cb(); - } -} - diff --git a/sitegin/output-filesystem.js b/sitegin/output-filesystem.js deleted file mode 100644 index fe92cc5083ea6dae232592a4d6dbe76268f6caa9..0000000000000000000000000000000000000000 --- a/sitegin/output-filesystem.js +++ /dev/null @@ -1,21 +0,0 @@ - -var fs = require('fs'); -var path = require('path'); -var mkdirp = require('mkdirp'); -var builddir = "build"; -if(process.argv[2] !== "compileonly") builddir = "build-debug"; - -module.exports = function() { - var out = this; - out.fancyname = "output filesystem"; - out.forEachPage = function(article, cb) { - mkdirp(path.dirname(builddir+'/'+article.file+"/index.html"), () => { - var file = builddir+'/'+article.file+"/index.html"; - fs.writeFile(file, article.content, function(err){ - if(err) throw err; - cb(); - }); - }); - } -} - diff --git a/sitegin/parseHugo.js b/sitegin/parseHugo.js new file mode 100644 index 0000000000000000000000000000000000000000..43af577af8a6a926e919e45a19320225dcfa0387 --- /dev/null +++ b/sitegin/parseHugo.js @@ -0,0 +1,39 @@ +var toml = require('toml'); +var moment = require('moment'); +var path = require('path'); +var jsesc = require('jsesc') + +var readPageWorker = function(content, obj) { + if(content === undefined) throw new Error("content is undefined"); + var head = content.substring(0,4) + if(head !== '+++\n') + throw new Error('Failed to parse file '+obj.filename+':\n'+ + 'Wrong header (expected "+++\\n" got "'+jsesc(head)+'")') + + content = content.substring(4); + var fm_end = content.indexOf("+++\n"); + if(fm_end < 0) { + console.log(jsesc(content)); + throw new Error('Cannot find terminating +++\n in file '+obj.filename); + } + obj.content = content.substring(fm_end+4); + try { + obj.metadata = toml.parse(content.substring(0,fm_end-1)+"\n"); + } catch(e) { + console.log(obj.filename+": Failed to parse metadata"); + throw e; + } + if(obj.metadata.date && obj.metadata.date.creation) obj.metadata.date.creation = moment(obj.metadata.date.creation); + return obj; +} + +module.exports = function(obj) { + return new Promise(function(resolve, reject) { + var pages = []; + obj.pages.forEach(function(page) { + pages.push(readPageWorker(page.content, page)); + }) + obj.pages = pages; + resolve(obj); + }); +} diff --git a/sitegin/pipeline.js b/sitegin/pipeline.js new file mode 100644 index 0000000000000000000000000000000000000000..7bc89858899261bf76f44fb94436aea9f0e0499c --- /dev/null +++ b/sitegin/pipeline.js @@ -0,0 +1,18 @@ +/* + * This jobs just runs all job in the right order + */ + +module.exports = function(jobs) { + return jobs.runSequence( + 'config', + 'readFiles', + 'parseHugo', + 'gitInfo', + 'urls', + 'markdown', + 'tags', + 'theme', + 'writeFiles', + 'print' + ); +} diff --git a/sitegin/print.js b/sitegin/print.js new file mode 100644 index 0000000000000000000000000000000000000000..01fda30c8e409d84e6489bc57b7d49a826284303 --- /dev/null +++ b/sitegin/print.js @@ -0,0 +1,29 @@ +var util = require('util') + +module.exports = function(a) { + var save = {}; + var savec = {}; + var props = []; + var shortenProp = function(prop) { + if(a[prop]) { + save[prop] = a[prop]; + a[prop] = [a[prop][0]]; + savec[prop] = a[prop][0].content; + a[prop][0].content = '...'; + props.push(prop); + } + } + + shortenProp('pages') + shortenProp('tags') + shortenProp('redirects') + + console.log(util.inspect(a,null,2)) + + props.forEach(function(prop){ + a[prop] = save[prop]; + a[prop][0].content = savec[prop]; + }); + + return Promise.resolve(a) +} diff --git a/sitegin/readFiles.js b/sitegin/readFiles.js new file mode 100644 index 0000000000000000000000000000000000000000..83fa9a5ae560c0e317ecd9ba1a637825cc0af354 --- /dev/null +++ b/sitegin/readFiles.js @@ -0,0 +1,38 @@ +/* + * This job reads files from config.articlesLocation and loads this list to `pages` + */ +var walk = require('walk'); +var fs = require('fs'); +var path = require('path'); + +module.exports = function(obj) { + return new Promise(function(resolve, reject) { + var pages = []; + walk.walk(path.join(obj.config.sourceDir,obj.config.articlesLocation)) + .on('file',function(root, fileStats, next) { + var filename = path.join(root,fileStats.name); + var file = path.relative(obj.config.sourceDir, filename); + fs.readFile(filename, 'utf8', function(err,data) { + if(err) { + console.log('Error reading file '+filename) + console.log(err); + } else { + pages.push({ + filename: filename, + file: file, + content: data + }) + } + next() + }) + }) + .on('errors',function(root, nodeStatsArray, next) { + console.log('Walker error', root, nodeStatsArray); + next(); + }) + .on('end', function() { + obj.pages = pages; + resolve(obj); + }) + }) +} diff --git a/sitegin/sequencer.js b/sitegin/sequencer.js deleted file mode 100644 index b5c271da37c4c84bf18a83dd91e3e89ed668893a..0000000000000000000000000000000000000000 --- a/sitegin/sequencer.js +++ /dev/null @@ -1,59 +0,0 @@ -module.exports = function() { - var t = this; - var lastEvent; - this.load = function(input) { - lastEvent = input.fancyname+" done"; - input.getPageList(function(list) { - t.emit(input.fancyname+" done", list); - }); - return this; - } - - this.registerNext = function(obj) { - // pre - t.on(lastEvent, function(list) { - if(obj.pre !== undefined) { - obj.pre(function() { - t.emit(obj.fancyname+' pre done', list); - }, list); - } else { - t.emit(obj.fancyname+' pre done', list); - } - }); - // forEachPage - t.on(obj.fancyname+' pre done', function(list) { - var transforming = list.length; - if(obj.forEachPage !== undefined) { - list.forEach(function(article) { - obj.forEachPage(article, function() { - transforming--; - if(transforming == 0) { - t.emit(obj.fancyname+' forEachPage done', list); - } - }); - }); - } else { - t.emit(obj.fancyname+' forEachPage done', list); - } - }); - // post - t.on(obj.fancyname+' forEachPage done', function(list) { - if(obj.post !== undefined) { - obj.post(function() { - t.emit(obj.fancyname+' post done', list); - }, list) - } else { - t.emit(obj.fancyname+' post done', list); - } - }); - - lastEvent = obj.fancyname+' post done'; - return this; - } - - this.finish = function(f) { - t.on(lastEvent, f); - } -} - -module.exports.prototype.__proto__ = require('events').EventEmitter.prototype; diff --git a/sitegin/sitegin.js b/sitegin/sitegin.js index f7a4a9256e2274704eee5d8e37c6db86abadebd1..97bb02aa380c97ecc973a71ad7f8e89fdb9c4cad 100644 --- a/sitegin/sitegin.js +++ b/sitegin/sitegin.js @@ -1,22 +1,24 @@ -exports.input = { - Hugo: require('./input-hugo') -} +var jobs = require('./jobs'); -exports.output = { - Console: require('./output-console'), - Filesystem: require('./output-filesystem') -} +module.exports = function(config) { + return jobs.registerMultiple( + config, + ['config', './config'], + ['gitInfo', './gitInfo'], + ['markdown', './markdown'], + ['parseHugo', './parseHugo'], + ['print', './print'], + ['readFiles', './readFiles'], + ['toURL', './toURL'], + ['tags', './tags'], + ['nunjucks', './nunjucks'], + ['theme', './theme'], + ['urls', './urls'], + ['writeFiles', './writeFiles'], -exports.transformer = { - Basichtml: require('./transformer-basichtml'), - Git: require('./transformer-git'), - Markdown: require('./transformer-markdown'), - Nunjucks: require('./transformer-nunjucks'), - Tags: require('./transformer-tags'), - UrlizeTags: require('./transformer-urlizetags'), - Other: require('./transformer-other'), - Images: require('./transformer-images'), + ['pipeline','./pipeline'] + ) + .then(function() { + return jobs; + }) } - -exports.Page = require('./Page'); -exports.Sequencer = require('./sequencer'); diff --git a/sitegin/transformer-tags.js b/sitegin/tags.js similarity index 63% rename from sitegin/transformer-tags.js rename to sitegin/tags.js index 22faaff2bc36c50c2e8b08ed8362bb326e9a6362..2e27c8dcef14b13b184f105d321f72fb3c987809 100644 --- a/sitegin/transformer-tags.js +++ b/sitegin/tags.js @@ -1,29 +1,41 @@ -var Page = require("./Page.js").Page; var moment = require('moment'); +var jobs = require('./jobs'); -module.exports = function() { - var tr = this; - tr.fancyname = "transformer tags"; - tr.linksPerPage = 6; - tr.pre = function(cb, list) { +var toURL = function(url) { + return jobs.run('toURL', url); +} + +module.exports = function(obj) { + return new Promise(function(resolve, reject) { var tags = new Array(); var tagPages = {}; - list.forEach(function(article) { - if(article.metadata.tags) - article.metadata.tags.forEach(function(tag) { - if(tags.map(function(e) { return e.url; }).indexOf(tag.url) < 0) - tags.push(tag) - if(tagPages[tag.url] == undefined) tagPages[tag.url] = new Array(); - tagPages[tag.url].push(article) - }) + obj.pages.forEach(function(article) { + if(article.metadata.tags) { + var ntags = []; + article.metadata.tags.forEach(function(tag) { + tag = { + text: tag, + url: toURL(tag) + } + ntags.push(tag); + if(tags.map(function(e) { return e.url; }).indexOf(tag.url) < 0) + tags.push(tag) + if(tagPages[tag.url] == undefined) tagPages[tag.url] = new Array(); + tagPages[tag.url].push(article) + }) + article.metadata.tags = ntags; + } }); + obj.tags = []; + obj.redirects = []; + var generateTagPages = function(file, pageList) { - var p = new Page(); + var p = {}; p.type = "redirect"; p.file = file; p.content = file+"/1"; - list.addPage(p); + obj.redirects.push(p); pageList.sort(function (a, b) { var rhs = a.metadata.date.creation; @@ -43,10 +55,10 @@ module.exports = function() { p++; if(tagPage !== undefined) { tagPage.metadata.nexturl = file+"/"+p; - list.addPage(tagPage); + obj.tags.push(tagPage); tagPageList.push(tagPage); } - tagPage = new Page(); + tagPage = {metadata: {}}; if(firstpage === undefined) firstpage = tagPage; lastpage = tagPage; @@ -57,7 +69,7 @@ module.exports = function() { tagPage.metadata.prevurl = prevurl; tagPage.metadata.thispage = tagPage; tagPage.metadata.pagenumber = p; - + tagPage.content = new Array(); if(prevpage !== undefined) prevpage.metadata.nextpage = tagPage; @@ -67,20 +79,18 @@ module.exports = function() { tagPage.content.push(page); c++; - c %= tr.linksPerPage; + c %= obj.config.linksPerPage; }); - list.addPage(tagPage); + obj.tags.push(tagPage); tagPageList.push(tagPage); tagPageList.forEach(function(tagPage) { tagPage.metadata.lastpage = lastpage; }); } - tags.forEach(function(tag) { generateTagPages("tag/"+tag.url, tagPages[tag.url]) }) - cb(); - } + resolve(obj); + }) } - diff --git a/sitegin/theme.js b/sitegin/theme.js new file mode 100644 index 0000000000000000000000000000000000000000..aab5d9db9f7a23aa0e548f8ba8fc9941a5e14c9e --- /dev/null +++ b/sitegin/theme.js @@ -0,0 +1,31 @@ +var jobs = require('./jobs'); + +module.exports = function(obj) { + return new Promise(function(resolve,reject){ + var todo = 0; + var done = function(){ + todo--; if(todo <= 0) resolve(obj); + } + + var runJob = function(obj, type) { + todo++; + jobs.run('nunjucks', obj, type) + .then(function(data) { + obj.content = data; + done(); + }) + .catch(function(e) {reject(e)}) + } + + obj.pages.forEach(function(page) { + runJob(page,'article') + }) + obj.tags.forEach(function(tag) { + runJob(tag,'tag') + }) + obj.redirects.forEach(function(redirect) { + runJob(redirect,'redirect') + }) + if(todo <= 0) resolve(obj); + }) +} diff --git a/sitegin/transformer-urlizetags.js b/sitegin/toURL.js similarity index 93% rename from sitegin/transformer-urlizetags.js rename to sitegin/toURL.js index 0d3069f92e7d49e996ed963b040c9ca170fb2afe..d94e805607e69fe72284b8645b79b9c6711426ba 100644 --- a/sitegin/transformer-urlizetags.js +++ b/sitegin/toURL.js @@ -4,30 +4,7 @@ String.prototype.latinise=function(){return this.replace(/[^A-Za-z0-9\[\] ]/g,fu String.prototype.latinize=String.prototype.latinise; String.prototype.isLatin=function(){return this==this.latinise()} -var toURL = function(tag) { +module.exports = function(tag) { if(tag == undefined) return undefined; - return tag.toLowerCase().latinise().replace(/ /g,"-"); + return tag.toLowerCase().latinise().replace(/ /g,"-");; } - -var f = function() { - var tr = this; - tr.fancyname = "transformer urlizetags"; - tr.toURL = toURL; - tr.forEachPage = function(article, cb) { - var ntags = []; - if(article.metadata.tags) { - article.metadata.tags.forEach(function(tag) { - var ntag = {}; - ntag.text = tag; - ntag.url = tr.toURL(tag); - ntags.push(ntag); - }); - article.metadata.tags = ntags; - } - cb(); - } -} - -f.toURL = toURL; - -module.exports = f; diff --git a/sitegin/transformer-basichtml.js b/sitegin/transformer-basichtml.js deleted file mode 100644 index 3ca958cfd51512aa7a916cdd2be4231919563a24..0000000000000000000000000000000000000000 --- a/sitegin/transformer-basichtml.js +++ /dev/null @@ -1,12 +0,0 @@ - -module.exports = function() { - var tr = this; - tr.fancyname = "transformer basichtml"; - tr.forEachPage = function(article, cb) { - article.content = "<!DOCTYPE html><html><meta charset=\"UTF-8\" /><head><title>" - +article.metadata.title+ - "</title></head><body>" + article.content + "</body></html>"; - cb(); - } -} - diff --git a/sitegin/transformer-images.js b/sitegin/transformer-images.js deleted file mode 100644 index b764a473d2d6fef737b6e6cd2676a0cf8ca35925..0000000000000000000000000000000000000000 --- a/sitegin/transformer-images.js +++ /dev/null @@ -1,97 +0,0 @@ -var input = new (require('./input-hugo')); -var lwip; -try {lwip = require('lwip');} -catch(e) { - lwip = null - console.log("WARNING! LWIP is not installed - image minification won't work."); - console.log("You can try to run npm install."); - console.log("If it doesn't help try to make npm install lwip work."); -} -var path = require('path'); - -var builddir = "build"; -if(process.argv[2] !== "compileonly") builddir = "build-debug"; - -var minify = function() { - return Promise.resolve(new Promise(function(resolve, reject) { - var fileList = []; - input.walk('static/', - function(file, stat) { - if(file.match(/\.png$/i) || file.match(/\.jpe?g$/i)) { - fileList.push(file); - } - }, - function() { - resolve(fileList); - } - ); - })).then(function(fileList) { - var promises = []; - fileList.forEach((file) => { - file = file.split(path.sep).join('/'); - var f = file.split("."); - var ext = f.splice(-1,1); - f = f.join("."); - f = f+"_thumbnail."+ext; - f = f.split('/'); - f.splice(0,1,builddir); - f = f.join('/').replace('articles','clanek'); - - var minifyPromise = function(resolve, reject) { - if(lwip) { - lwip.open(file, function(err, image) { - if(err) throw err; - var w = image.width(), h = image.height(); - if(w <= 512) { - file = file.replace("static/","").replace('articles','clanek'); - resolve({ - minified: false, - file: file, - thumb: file - }); - } else { - image.batch() - .resize(512, Math.round(512*h/w)) - .writeFile(f, function(err) { - if(err) throw err; - resolve({ - minified: true, - file: file.replace("static/","").replace('articles','clanek'), - thumb: f.replace(builddir+'/',"") - }); - }); - } - }) - } else { - file = file.replace("static/","").replace('articles','clanek'); - resolve({ - minified: false, - file: file, - thumb: file - }); - } - } - - promises.push(new Promise(minifyPromise)); - }); - return Promise.all(promises); - }) -} - -module.exports = function() { - var tr = this; - tr.fancyname = "transformer images"; - tr.pre = function(cb, list) { - if(process.argv[2] == "compileonly") { - minify() - .then(function(imageList) { - list.images = imageList; - cb(); - }) - .catch(function(err) {console.log(err.stack); cb();}); - } else { - console.log("Skipping image minification"); - cb(); - } - } -} diff --git a/sitegin/transformer-nunjucks.js b/sitegin/transformer-nunjucks.js deleted file mode 100644 index 0471fee577308c6f6630a6eb1e8c5e87aeab46b8..0000000000000000000000000000000000000000 --- a/sitegin/transformer-nunjucks.js +++ /dev/null @@ -1,68 +0,0 @@ -var nunjucks = require('nunjucks'); -var fs = require('fs'); -var dateFilter = require('nunjucks-date-filter'); -var util = require('util'); - -var MyLoader = nunjucks.Loader.extend({ - fileSystemLoader: {}, - init: function(searchPaths, opts) { - fileSystemLoader = new nunjucks.FileSystemLoader(searchPaths, opts); - }, - - getSource: function(name) { - return fileSystemLoader.getSource(name+".html.nunjucks"); - } -}); - - -module.exports = function() { - var tr = this; - var templates = {}; - tr.pre = function(cb) { - var env = new nunjucks.Environment(new MyLoader('theme/templates',{watch: process.argv[2] !== "compileonly"})); - env.addFilter('date', dateFilter); - - env.addFilter('paginationList', function(page, count) { - var curPage = page; - var pages = []; - pages.push(curPage); - for(var i = 0; i < count; i++) { - curPage = curPage.metadata.prevpage; - if(curPage === undefined) break; - pages.unshift(curPage); - } - - curPage = page; - for(var i = 0; i < count; i++) { - curPage = curPage.metadata.nextpage; - if(curPage === undefined) break; - pages.push(curPage); - } - return pages; - }); - - env.addFilter('inspect', function(obj) { - return util.inspect(obj); - }); - - - templates["article"] = env.getTemplate('article'); - templates["tag"] = env.getTemplate('tag'); - templates["redirect"] = env.getTemplate('redirect'); - cb(); - }; - - tr.fancyname = "transformer nunjucks"; - - tr.forEachPage = function(page, cb) { - page.config = { - baseurl: "", - devel: process.argv[2] !== "compileonly" - } - var html = templates[page.type].render(page); - //if(page.type == "tag") console.log(page.content[0].file); - page.content = html; - cb(); - } -} - diff --git a/sitegin/transformer-other.js b/sitegin/transformer-other.js deleted file mode 100644 index b948057ec99cb5ecf3d99abae11e069f042da897..0000000000000000000000000000000000000000 --- a/sitegin/transformer-other.js +++ /dev/null @@ -1,18 +0,0 @@ -var path = require('path'); -module.exports = function() { - var tr = this; - tr.fancyname = "transformer other"; - tr.forEachPage = function(article, cb) { - var img = article.metadata.image; - article.file = article.file.split(path.sep).join("/"); - if(img) { - if(!img.match(/^\//)) { - article.metadata.image = article.file+"/"+img; - } else { - article.metadata.image = img.replace("/",""); - } - } - - cb(); - } -} diff --git a/sitegin/urls.js b/sitegin/urls.js new file mode 100644 index 0000000000000000000000000000000000000000..11693250eded17a113efbd10eb2be356fa135f42 --- /dev/null +++ b/sitegin/urls.js @@ -0,0 +1,15 @@ +/* + * This jobs translates files to resulting URL + */ + +module.exports = function(obj) { + return new Promise(function(resolve, reject) { + obj.pages.forEach(function(page) { + var file = page.file; + file = file.replace(/\.md$/,''); + file = file.replace(/^articles/,'clanek'); + page.file = file; + }) + resolve(obj) + }); +} diff --git a/sitegin/writeFiles.js b/sitegin/writeFiles.js new file mode 100644 index 0000000000000000000000000000000000000000..04a17fd0a6e11e9989250e7f189c0e7e3e9e3d01 --- /dev/null +++ b/sitegin/writeFiles.js @@ -0,0 +1,26 @@ + +var fs = require('fs'); +var path = require('path'); +var mkdirp = require('mkdirp'); + +module.exports = function(obj) { + return new Promise(function(resolve,reject) { + var builddir = obj.config.builddir; + var todo = 0; + + var writeFile = function(article) { + var filename = path.join(builddir,article.file,"index.html"); + mkdirp(path.dirname(filename), function() { + fs.writeFile(filename, article.content, function(err) { + if(err) reject(err); + todo--; + if(todo <= 0) resolve(obj); + }); + }); + } + obj.pages.forEach(function(o) { writeFile(o); }) + obj.redirects.forEach(function(o) { writeFile(o); }) + obj.tags.forEach(function(o) { writeFile(o); }) + if(todo <= 0) resolve(obj); + }) +} diff --git a/theme/templates/404.html.nunjucks b/theme/templates/404.html.nunj similarity index 100% rename from theme/templates/404.html.nunjucks rename to theme/templates/404.html.nunj diff --git a/theme/templates/article.html.nunjucks b/theme/templates/article.html.nunj similarity index 89% rename from theme/templates/article.html.nunjucks rename to theme/templates/article.html.nunj index 090aeadf9f8bab3e183d9765c6bc61b933e7cc2e..afca50de2c4054598dd3abacfb8fded3f4d6340d 100644 --- a/theme/templates/article.html.nunjucks +++ b/theme/templates/article.html.nunj @@ -1,4 +1,8 @@ -{% include "partials/header" %} +{% extends "partials/base.html.nunj" %} + +{% block bodyattr %} class="type-article"{% endblock %} + +{% block content %} <div class="section container" id="content"> <div class="metadata"> <h2 id="title">{{ metadata.title }}</h2> @@ -30,4 +34,4 @@ </p> </article> </div> -{% include "partials/footer" %} +{% endblock %} diff --git a/theme/templates/gallery.html.nunjucks b/theme/templates/gallery.html.nunjucks deleted file mode 100644 index 8cea0527492445075ae5c2e34944234b8d938bbe..0000000000000000000000000000000000000000 --- a/theme/templates/gallery.html.nunjucks +++ /dev/null @@ -1,3 +0,0 @@ -{{ include "partials/header.html" }} - -{{ include "partials/footer.html" }} diff --git a/theme/templates/partials/header.html.nunjucks b/theme/templates/partials/base.html.nunj similarity index 80% rename from theme/templates/partials/header.html.nunjucks rename to theme/templates/partials/base.html.nunj index 0c5b81765e82f0874b296e105993c3a92ee9398c..83d92a22eff2c694c4c1c260cb85941510aad4dc 100644 --- a/theme/templates/partials/header.html.nunjucks +++ b/theme/templates/partials/base.html.nunj @@ -38,8 +38,8 @@ {% endif %} {{ metadata.headerextra | safe }} </head> -<body {{ "class=type-article" if type=="article" }}> - {% import "partials/svgs" as svgs %} +<body{% block bodyattr %}{% endblock %}> + {% import "partials/svgs.html.nunj" as svgs %} <div id="all"> <!-- Top nav --> <nav class="supernav" role="navigation" style="z-index:5;position:absolute;"> @@ -141,5 +141,51 @@ </ul> </div> </nav> - {% include "partials/search" %} - + {% include "partials/search.html.nunj" %} + + {% block content %} + {% endblock %} + + <footer class="page-footer blue"> + <div class="container s6"> + <a class="orange-text text-lighten-3" href="https://git.ok1kvk.cz/">Gitlab</a> | + <a class="orange-text text-lighten-3" href="https://ok1kvk.cz/forum">Fórum</a> | + <a class="orange-text text-lighten-3">Webkamera</a> + {% if type=="article" %} + | <a class="orange-text text-lighten-3" href="https://git.ok1kvk.cz/ok1kvk.cz/content/tree/master/articles/{{file | replace("clanek/","")}}.md">Zdroják tohoto Älánku</a> + {% endif %} + </div> + <div class="container s6"> + Stránky pro OK1KVK vytvoÅ™il <a class="orange-text text-lighten-3">Jakub SkoÅ™epa</a> 2015-2016 + </div> + </footer> + + <script src="{{ config.baseurl }}/theme/js/materialize.js"></script> + <script src="{{ config.baseurl }}/theme/js/init.js"></script> + + <script> + (function($) { + var onresize = function(){ + $("footer").height("auto"); + $("#content").css("margin-bottom",$("footer").height()); + }; + $(window).resize(onresize); + $(document).load(onresize); + $(document).ready(onresize); + })(jQuery); + </script> + {% if not config.debug %} + <script> + (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ + (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), + m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) + })(window,document,'script','//www.google-analytics.com/analytics.js','ga'); + + ga('create', 'UA-74646565-1', 'auto'); + ga('send', 'pageview'); + + </script> + {% endif %} + <script src="{{ config.baseurl }}/theme/lightbox2/dist/js/lightbox.min.js"></script> + </body> +</html> diff --git a/theme/templates/partials/footer.html.nunjucks b/theme/templates/partials/footer.html.nunjucks deleted file mode 100644 index 2b2c3734de6178727c3f1237b630fc4e492851f1..0000000000000000000000000000000000000000 --- a/theme/templates/partials/footer.html.nunjucks +++ /dev/null @@ -1,44 +0,0 @@ - <footer class="page-footer blue"> - <div class="container s6"> - <a class="orange-text text-lighten-3" href="https://git.ok1kvk.cz/">Gitlab</a> | - <a class="orange-text text-lighten-3" href="https://ok1kvk.cz/forum">Fórum</a> | - <a class="orange-text text-lighten-3">Webkamera</a> - {% if type=="article" %} - | <a class="orange-text text-lighten-3" href="https://git.ok1kvk.cz/ok1kvk.cz/content/tree/master/articles/{{file | replace("clanek/","")}}.md">Zdroják tohoto Älánku</a> - {% endif %} - </div> - <div class="container s6"> - Stránky pro OK1KVK vytvoÅ™il <a class="orange-text text-lighten-3">Jakub SkoÅ™epa</a> 2015-2016 - </div> - </footer> - - <script src="{{ config.baseurl }}/theme/js/materialize.js"></script> - <script src="{{ config.baseurl }}/theme/js/init.js"></script> - - </div> <!-- #wrapper --> - <script> - (function($) { - var onresize = function(){ - $("footer").height("auto"); - $("#content").css("margin-bottom",$("footer").height()); - }; - $(window).resize(onresize); - $(document).load(onresize); - $(document).ready(onresize); - })(jQuery); - </script> - {% if not config.debug %} - <script> - (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ - (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), - m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) - })(window,document,'script','//www.google-analytics.com/analytics.js','ga'); - - ga('create', 'UA-74646565-1', 'auto'); - ga('send', 'pageview'); - - </script> - {% endif %} - <script src="{{ config.baseurl }}/theme/lightbox2/dist/js/lightbox.min.js"></script> - </body> -</html> diff --git a/theme/templates/partials/list.html.nunjucks b/theme/templates/partials/list.html.nunj similarity index 95% rename from theme/templates/partials/list.html.nunjucks rename to theme/templates/partials/list.html.nunj index 8c4a2f7f4c9631e4ee71a81c8fc936b198bea75a..c40b1a05aa822ae0f3e8f9318ed7f7bb190016c1 100644 --- a/theme/templates/partials/list.html.nunjucks +++ b/theme/templates/partials/list.html.nunj @@ -1,4 +1,4 @@ -{% import "partials/svgs" as svgs %} +{% import "partials/svgs.html.nunj" as svgs %} <div id=content class=container> <div class="section"> <div class="row"> @@ -8,7 +8,7 @@ <div class="block article" style=""> <a href="{{ config.baseurl }}/{{ page.file }}"> <div style="height:120px; - {% if page.metadata.image %}background-image: url('{{config.baseurl}}/{{ page.metadata.image }}'){% endif %} + {% if page.metadata.image %}background-image: url('{{ config.baseurl }}{{ page.metadata.image | relURL(page.file) }}'){% endif %} " class="leadimage light-blue darken-2"></div> </a> <div class="head-title"> @@ -35,8 +35,8 @@ </div> {% endfor %} </div> - - {% include "partials/paginator" %} + + {% include "partials/paginator.html.nunj" %} </div> <div class="hide-on-small-only"> @@ -62,21 +62,21 @@ if ($(this).height() > maxHeight) { maxHeight = $(this).height(); } }); $(".head-perex").height(maxHeight); - + $(".head-title").height("auto"); maxHeight = 0; $(".head-title").each(function(){ if ($(this).height() > maxHeight) { maxHeight = $(this).height(); } }); $(".head-title").height(maxHeight); - + $(".head-info").height("auto"); maxHeight = 0; $(".head-info").each(function(){ if ($(this).height() > maxHeight) { maxHeight = $(this).height(); } }); $(".head-info").height(maxHeight); - + // Sidelink icons of same size $(".sidelink-icon").css("top",$(window).height()/2); }; diff --git a/theme/templates/partials/paginator.html.nunjucks b/theme/templates/partials/paginator.html.nunj similarity index 96% rename from theme/templates/partials/paginator.html.nunjucks rename to theme/templates/partials/paginator.html.nunj index e2a618ffb28c6a2c7ba256dc3b83abf6b497dbdc..f81ce3a5c477546af918c3cd44488bc027c73bdd 100644 --- a/theme/templates/partials/paginator.html.nunjucks +++ b/theme/templates/partials/paginator.html.nunj @@ -1,4 +1,4 @@ -{% import "partials/svgs" as svgs %} +{% import "partials/svgs.html.nunj" as svgs %} <ul class="pagination"> <li><a {{ (" href=\""+config.baseurl +"/"+ metadata.firstpage.file +"\"") | safe if metadata.firstpage.file != file }}> @@ -17,9 +17,8 @@ <li><a {{ " href="+config.baseurl +"/"+ metadata.nextpage.file if metadata.nextpage != undefined }}> {{ svgs.chevronright( "#999" if metadata.nextpage == undefined else "#000", 1,"em" ) }} </a></li> - + <li><a {{ (" href=\""+config.baseurl +"/"+ metadata.lastpage.file +"\"") | safe if metadata.lastpage.file != file }}> {{ svgs.doublechevronright( "#999" if metadata.lastpage.file == file else "#000", 1,"em" ) }} </a></li> </ul> - diff --git a/theme/templates/partials/search.html.nunjucks b/theme/templates/partials/search.html.nunj similarity index 100% rename from theme/templates/partials/search.html.nunjucks rename to theme/templates/partials/search.html.nunj diff --git a/theme/templates/partials/svgs.html.nunjucks b/theme/templates/partials/svgs.html.nunj similarity index 100% rename from theme/templates/partials/svgs.html.nunjucks rename to theme/templates/partials/svgs.html.nunj diff --git a/theme/templates/redirect.html.nunjucks b/theme/templates/redirect.html.nunj similarity index 100% rename from theme/templates/redirect.html.nunjucks rename to theme/templates/redirect.html.nunj diff --git a/theme/templates/tag.html.nunj b/theme/templates/tag.html.nunj new file mode 100644 index 0000000000000000000000000000000000000000..b086b5c739a3bbff12d526be441cd3c8f1867783 --- /dev/null +++ b/theme/templates/tag.html.nunj @@ -0,0 +1,5 @@ +{% extends "partials/base.html.nunj" %} + +{% block content %} + {% include "partials/list.html.nunj" %} +{% endblock %} diff --git a/theme/templates/tag.html.nunjucks b/theme/templates/tag.html.nunjucks deleted file mode 100644 index 7ec1cad9b36c5d62b55ab81ad55f220bd78ea398..0000000000000000000000000000000000000000 --- a/theme/templates/tag.html.nunjucks +++ /dev/null @@ -1,3 +0,0 @@ -{% include "partials/header" %} -{% include "partials/list" %} -{% include "partials/footer" %}