works
This commit is contained in:
parent
38b02c1c3b
commit
98251b3a68
|
@ -13,4 +13,12 @@
|
|||
, "unused": true
|
||||
, "latedef": true
|
||||
, "globals": { "angular": true }
|
||||
|
||||
, "bitwise": true
|
||||
, "curly": true
|
||||
, "forin": true
|
||||
, "freeze": true
|
||||
, "immed": true
|
||||
|
||||
, "funcscope": false
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ angular.module('myApp.services', []).
|
|||
return d.promise;
|
||||
}
|
||||
|
||||
Desi.build(desi, env).then(function () {
|
||||
Desi.buildAll(desi, env).then(function () {
|
||||
d.resolve(desi);
|
||||
});
|
||||
|
||||
|
|
507
deardesi.js
507
deardesi.js
|
@ -4,7 +4,6 @@
|
|||
var PromiseA = exports.Promise || require('bluebird').Promise
|
||||
, path = exports.path || require('path')
|
||||
, Mustache = exports.Mustache || require('mustache')
|
||||
, marked = (exports.markdownit || require('markdown-it'))({ html: true, linkify: true })
|
||||
, forEachAsync = exports.forEachAsync || require('foreachasync').forEachAsync
|
||||
//, sha1sum = exports.sha1sum || require('./lib/deardesi-node').sha1sum
|
||||
, frontmatter = exports.Frontmatter || require('./lib/frontmatter').Frontmatter
|
||||
|
@ -29,6 +28,19 @@
|
|||
, 12: 'December'
|
||||
};
|
||||
|
||||
/*
|
||||
function shallowClone(obj) {
|
||||
var shallow = {}
|
||||
;
|
||||
|
||||
Object.keys(obj).forEach(function (key) {
|
||||
shallow[key] = obj[key];
|
||||
});
|
||||
|
||||
return shallow;
|
||||
}
|
||||
*/
|
||||
|
||||
function firstCap(str) {
|
||||
return str.replace(/^./, function ($1) { return $1.toUpperCase(); });
|
||||
}
|
||||
|
@ -154,6 +166,7 @@
|
|||
}
|
||||
|
||||
function getLayout(desi, themename, layout, arr) {
|
||||
// TODO meta.layout for each entity
|
||||
arr = arr || [];
|
||||
|
||||
var layoutdir = 'layouts'
|
||||
|
@ -176,6 +189,7 @@
|
|||
// TODO what if it isn't html?
|
||||
if (theme.path === themepath || theme.path.match(themepath + '\\.html')) {
|
||||
file = theme;
|
||||
theme.ext = path.extname(file.path);
|
||||
arr.push(theme);
|
||||
return true;
|
||||
}
|
||||
|
@ -224,8 +238,8 @@
|
|||
console.info('loaded config, data, caches, partials');
|
||||
console.log({
|
||||
config: arr.config
|
||||
, data: arr.data
|
||||
, site: arr.site
|
||||
, authors: arr.authors
|
||||
});
|
||||
|
||||
desi.blogdir = blogdir;
|
||||
|
@ -339,22 +353,7 @@
|
|||
});
|
||||
};
|
||||
|
||||
Desi.setEnv = function (desi, env) {
|
||||
desi.urls = desi.config.urls = {};
|
||||
desi.env = {};
|
||||
if (-1 === ['development', 'staging'].indexOf(env) || !desi.config[env]) {
|
||||
env = 'production';
|
||||
}
|
||||
|
||||
desi.urls.base_path = desi.config.base_path = desi.config[env].base_path;
|
||||
desi.urls.url = desi.config[env].url;
|
||||
desi.config.compiled_path = desi.config[env].compiled_path;
|
||||
desi.urls[env + '_url'] = desi.config[env].url;
|
||||
|
||||
return PromiseA.resolve(desi);
|
||||
};
|
||||
|
||||
Desi.getDirtyFiles = function (desi, env) {
|
||||
Desi.getDirtyFiles = function (desi) {
|
||||
var cache = desi.cache
|
||||
//, config = desi.config
|
||||
, cacheByPath = {}
|
||||
|
@ -364,10 +363,6 @@
|
|||
, droot
|
||||
;
|
||||
|
||||
if (!desi.env) {
|
||||
Desi.setEnv(desi, env);
|
||||
}
|
||||
|
||||
cache.sources = cache.sources || [];
|
||||
cache.sources.forEach(function (source) {
|
||||
cacheByPath[source.path] = source;
|
||||
|
@ -419,7 +414,7 @@
|
|||
});
|
||||
};
|
||||
|
||||
Desi.copyAssets = function(desi) {
|
||||
Desi.copyAssets = function(desi, env) {
|
||||
var files = {}
|
||||
;
|
||||
|
||||
|
@ -429,10 +424,9 @@
|
|||
var assets = desi.meta.assets[key]
|
||||
;
|
||||
|
||||
// TODO fix compiled_path + base_path
|
||||
assets.forEach(function (asset) {
|
||||
console.log('preparing ' + asset + ' for copy');
|
||||
files[path.join(asset.relativePath, asset.name)] = path.join(desi.config.compiled_path, 'assets', asset.relativePath, asset.name);
|
||||
console.log('preparing ' + asset.path + ' for copy');
|
||||
files[path.join(asset.relativePath, asset.name)] = path.join(env.compiled_path, 'assets', asset.relativePath, asset.name);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -464,25 +458,29 @@
|
|||
desi.navigation = [];
|
||||
|
||||
desi.content.root.forEach(function (page) {
|
||||
// XXX BUG TODO strip only strip _root so that nested nav will work as expected
|
||||
var name = path.basename(page.path, path.extname(page.path))
|
||||
, nindex
|
||||
;
|
||||
|
||||
//if (-1 === desi.data.navigation.indexOf(name) && 'index' !== name)
|
||||
nindex = desi.data.navigation.indexOf(name);
|
||||
nindex = (desi.site.navigation).indexOf(name);
|
||||
if (-1 === nindex) {
|
||||
return;
|
||||
}
|
||||
|
||||
desi.navigation[nindex] = {
|
||||
title: page.yml && page.yml.title || firstCap(name)
|
||||
, href: desi.urls.base_path + '/' + name
|
||||
, path: desi.urls.base_path + '/' + name
|
||||
, name: name
|
||||
, active: false // placeholder
|
||||
};
|
||||
});
|
||||
|
||||
// transform spare array into compact array
|
||||
desi.navigation = desi.navigation.filter(function (n) {
|
||||
return n;
|
||||
});
|
||||
|
||||
return PromiseA.resolve(desi);
|
||||
};
|
||||
|
||||
|
@ -557,7 +555,7 @@
|
|||
|
||||
if (!page.yml.date) {
|
||||
// TODO tell YAML parser to keep the date a string
|
||||
page.yml.date = new Date(page.yml.created_at || page.yml.time || page.createdDate || page.lastModifiedDate).toISOString();
|
||||
page.yml.date = new Date(page.yml.created_at || page.yml.time || page.yml.updated_at || page.createdDate || page.lastModifiedDate).toISOString();
|
||||
}
|
||||
if ('object' === typeof page.yml.date) {
|
||||
page.yml.date = page.yml.date.toISOString();
|
||||
|
@ -570,9 +568,6 @@
|
|||
|
||||
function normalizeContentEntity(entity) {
|
||||
entity.ext = path.extname(entity.path);
|
||||
entity.url = desi.urls.url + path.join(desi.urls.base_path, entity.yml.permalink);
|
||||
entity.canonical_url = desi.urls.url + path.join(desi.urls.base_path, entity.yml.permalink);
|
||||
entity.relative_url = path.join(desi.urls.base_path, entity.yml.permalink);
|
||||
entity.published_at = fromLocaleDate(entity.yml.date);
|
||||
entity.year = entity.published_at.year;
|
||||
entity.month = entity.published_at.month;
|
||||
|
@ -602,7 +597,7 @@
|
|||
return PromiseA.resolve(desi);
|
||||
};
|
||||
|
||||
Desi.collate = function (desi/*, collectionname*/) {
|
||||
Desi.collate = function (desi, env/*, collectionname*/) {
|
||||
function byDate(a, b) {
|
||||
if (a.year > b.year) {
|
||||
return -1;
|
||||
|
@ -651,6 +646,8 @@
|
|||
, mindex = 12 - f.month
|
||||
;
|
||||
|
||||
f.url = path.join(env.base_path, f.yml.permalink);
|
||||
|
||||
if (!yearsArr[yindex]) {
|
||||
yearsArr[yindex] = { year: f.year, months: [] };
|
||||
}
|
||||
|
@ -686,16 +683,218 @@
|
|||
|
||||
desi.content.collections.sort(byDate);
|
||||
desi.collated = collate(desi.content.collections);
|
||||
console.info('desi.collated');
|
||||
console.info('7 desi.collated');
|
||||
console.info(desi.collated);
|
||||
|
||||
return PromiseA.resolve(desi);
|
||||
};
|
||||
|
||||
Desi.build = function (desi) {
|
||||
Desi.datamaps = {};
|
||||
Desi.datamaps['desirae@1.0'] = function (obj) {
|
||||
obj.desi = obj;
|
||||
return obj;
|
||||
};
|
||||
Desi.datamaps['ruhoh@2.6'] = function (view) {
|
||||
var newview
|
||||
;
|
||||
|
||||
newview = {
|
||||
content: view.contents
|
||||
, page: {
|
||||
title: view.entity.yml.title || view.site.title
|
||||
, tagline: view.entity.yml.tagline
|
||||
, content: view.contents
|
||||
, youtube: view.entity.yml.youtube
|
||||
, disqus_identifier: view.entity.disqus_identifier
|
||||
, disqus_url: !view.entity.disqus_identifier && view.entity.disqus_url
|
||||
, tags: view.entity.yml.tags
|
||||
, categories: view.entity.yml.categories
|
||||
, player_width: view.entity.yml.player_width
|
||||
, player_height: view.entity.yml.player_height
|
||||
, next: view.entities[view.entity_index + 1]
|
||||
, previous: view.entities[view.entity_index - 1]
|
||||
, date: view.entity.year + '-' + view.entity.month + '-' + view.entity.day
|
||||
// TODO , url: view.entities.
|
||||
}
|
||||
, posts: { collated: view.desi.collated }
|
||||
, urls: {
|
||||
base_url: view.env.base_url
|
||||
, base_path: view.env.base_path
|
||||
}
|
||||
, data: {
|
||||
author: {
|
||||
name: view.author.name
|
||||
, twitter: view.author.twitter
|
||||
}
|
||||
, title: view.site.title
|
||||
}
|
||||
, assets: view.desi.assets.join('\n')
|
||||
, widgets: {
|
||||
comments: view.site.disqus_shortname &&
|
||||
Mustache.render(view.desi.partials.disqus, { disqus: {
|
||||
shortname: view.site.disqus_shortname
|
||||
, identifier: view.entity.disqus_identifier
|
||||
, url: !view.entity.disqus_identifier && view.entity.disqus_url
|
||||
}})
|
||||
, analytics: view.site.google_analytics_tracking_id &&
|
||||
Mustache.render(view.desi.partials.google_analytics, { google_analytics: {
|
||||
tracking_id: view.site.google_analytics_tracking_id
|
||||
}})
|
||||
, facebook_connect: view.desi.partials.facebook_connect
|
||||
, twitter: view.desi.partials.twitter
|
||||
, google_plusone: view.desi.partials.google_plusone
|
||||
, amazon_link_enhancer: view.site.amazon_affiliate_id &&
|
||||
Mustache.render(view.desi.partials.amazon_link_enhancer, {
|
||||
amazon_affiliate_id: view.site.amazon_affiliate_id
|
||||
})
|
||||
}
|
||||
, site: {
|
||||
navigation: view.navigation
|
||||
}
|
||||
};
|
||||
|
||||
// backwards compat
|
||||
newview.site['navigation?to_pages'] = newview.site.navigation;
|
||||
newview.site['navigation?to__root'] = newview.site.navigation;
|
||||
newview.data.navigation = view.site.navigation;
|
||||
newview.data['navigation?to_pages'] = newview.site.navigation;
|
||||
newview.data['navigation?to__root'] = newview.site.navigation;
|
||||
|
||||
newview.page.content = view.contents;
|
||||
|
||||
return newview;
|
||||
};
|
||||
|
||||
Desi.renderers = {};
|
||||
Desi.registerRenderer = function(ext, fn, opts) {
|
||||
// TODO allow a test method for ext and content (new RegExp("\\." + escapeRegExp(ext) + "$", i).test(current.ext))
|
||||
opts = opts || {};
|
||||
// TODO opts.priority
|
||||
Desi.renderers[ext] = Desi.renderers[ext] || [];
|
||||
// LIFO
|
||||
Desi.renderers[ext].unshift(fn);
|
||||
};
|
||||
Desi.render = function (ext, content, view) {
|
||||
ext = (ext||'').toLowerCase().replace(/^\./, '');
|
||||
|
||||
if (Desi.renderers[ext] && Desi.renderers[ext].length) {
|
||||
return Desi.renderers[ext][0](content, view);
|
||||
}
|
||||
return PromiseA.reject(new Error("no renderer registered for ." + ext));
|
||||
};
|
||||
|
||||
function registerJade() {
|
||||
var jade = true || exports.jade || require('jade')
|
||||
;
|
||||
|
||||
function render(contentstr/*, desi*/) {
|
||||
return PromiseA.resolve(jade(contentstr));
|
||||
}
|
||||
|
||||
if (false) {
|
||||
Desi.registerRenderer('jade', render);
|
||||
}
|
||||
}
|
||||
registerJade();
|
||||
|
||||
function registerMarkdown() {
|
||||
var markitdown = (exports.markdownit || require('markdown-it'))({ html: true, linkify: true })
|
||||
;
|
||||
|
||||
function render(contentstr/*, desi*/) {
|
||||
return Promise.resolve(
|
||||
markitdown.render(contentstr)
|
||||
//.replace('"', '"')
|
||||
//.replace(''', "'")
|
||||
//.replace('/', '/')
|
||||
);
|
||||
}
|
||||
|
||||
['md', 'markdown', 'mdown', 'mkdn', 'mkd', 'mdwn', 'mdtxt', 'mdtext'].forEach(function (ext) {
|
||||
Desi.registerRenderer(ext, render);
|
||||
});
|
||||
}
|
||||
registerMarkdown();
|
||||
|
||||
function registerHtml() {
|
||||
function render(contentstr/*, desi*/) {
|
||||
return PromiseA.resolve(contentstr);
|
||||
}
|
||||
|
||||
Desi.registerRenderer('html', render);
|
||||
Desi.registerRenderer('htm', render);
|
||||
Desi.registerRenderer('xhtml', render);
|
||||
}
|
||||
registerHtml();
|
||||
|
||||
function renderLayers(desi, env, view, entity) {
|
||||
var mustached = ''
|
||||
, layers
|
||||
;
|
||||
|
||||
layers = getLayout(desi, entity.yml.theme, entity.yml.layout, [entity]);
|
||||
// TODO inherit datamap from theme layout
|
||||
|
||||
return forEachAsync(layers, function (current) {
|
||||
var body = (current.body || current.contents || '').trim()
|
||||
;
|
||||
|
||||
// TODO move to normalization
|
||||
current.path = current.path || (entity.relativePath + '/' + entity.name);
|
||||
|
||||
|
||||
return Desi.render(current.ext, body, view).then(function (html) {
|
||||
var datamap = Desi.datamaps[env.datamap] || Desi.datamaps[entity.datamap] || Desi.datamaps['ruhoh@2.6']
|
||||
, newview
|
||||
;
|
||||
|
||||
view.contents = mustached;
|
||||
|
||||
// shallowClone to prevent perfect object equality (and potential template caching)
|
||||
if (/Blog$/.test(view.entity.title)) {
|
||||
console.log('desi.partials');
|
||||
console.log(desi.partials);
|
||||
}
|
||||
newview = datamap(view);
|
||||
if (/Blog$/.test(view.entity.title)) {
|
||||
console.info('desi.collated');
|
||||
console.log(desi);
|
||||
console.info('newview.posts.collated');
|
||||
console.log(newview.posts.collated);
|
||||
}
|
||||
mustached = Mustache.render(html, newview, desi.partials);
|
||||
|
||||
return mustached;
|
||||
}).catch(function (e) {
|
||||
console.error(current);
|
||||
if (env.onError) {
|
||||
return env.onError(e);
|
||||
} else {
|
||||
console.error('no registered renderer for ' + entity.path + ' or rendering failed');
|
||||
throw e;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Desi.build = function (desi, env) {
|
||||
var compiled = []
|
||||
;
|
||||
|
||||
env.transforms = env.transforms || [];
|
||||
desi.transforms = (desi.transforms || []).concat(env.transforms);
|
||||
desi.transforms.push(function (view) {
|
||||
var yml = view.entity.yml
|
||||
;
|
||||
|
||||
if (yml.uuid) {
|
||||
view.entity.disqus_identifier = yml.uuid;
|
||||
} else {
|
||||
view.entity.disqus_url = view.entity.production_url;
|
||||
}
|
||||
return view;
|
||||
});
|
||||
|
||||
/*
|
||||
function compileScriptEntity(entity, i, arr) {
|
||||
}
|
||||
|
@ -703,160 +902,154 @@
|
|||
function compileThemeEntity(entity, i, arr) {
|
||||
console.log("compiling " + (i + 1) + "/" + arr.length + " " + (entity.path || entity.name));
|
||||
// TODO less / sass / etc
|
||||
compiled.push({ contents: entity.body || entity.contents, path: path.join(desi.config.compiled_path, 'themes', entity.path) });
|
||||
compiled.push({ contents: entity.body || entity.contents, path: path.join('themes', entity.path) });
|
||||
if (/stylesheets.*\.css/.test(entity.path) && (!/google/.test(entity.path) || /obsid/.test(entity.path))) {
|
||||
// TODO XXX move to a partial
|
||||
desi.assets.push(
|
||||
'<link href="' + desi.urls.base_path + '/themes/' + entity.path + '" type="text/css" rel="stylesheet" media="all">'
|
||||
'<link href="' + env.base_path + '/themes/' + entity.path + '" type="text/css" rel="stylesheet" media="all">'
|
||||
);
|
||||
}
|
||||
}
|
||||
desi.navigation.filter(function (n) {
|
||||
return n;
|
||||
});
|
||||
//console.log(desi.navigation);
|
||||
function compileContentEntity(entity, i, arr) {
|
||||
console.log("compiling " + (i + 1) + "/" + arr.length + " " + (entity.path || entity.name));
|
||||
|
||||
var previous = ''
|
||||
, layers
|
||||
function compileContentEntity(entity, i, arr) {
|
||||
console.log("compiling " + (i + 1) + "/" + arr.length + " " + entity.path);
|
||||
|
||||
var navigation = JSON.parse(JSON.stringify(desi.navigation))
|
||||
, author = desi.authors[entity.yml.author] || desi.authors[Object.keys(desi.authors)[0]]
|
||||
, view
|
||||
;
|
||||
|
||||
layers = getLayout(desi, entity.yml.theme, entity.yml.layout, [entity]);
|
||||
entity.url = env.base_url + path.join(env.base_path, entity.yml.permalink);
|
||||
entity.canonical_url = env.base_url + path.join(env.base_path, entity.yml.permalink);
|
||||
entity.production_url = desi.site.base_url + path.join(desi.site.base_path, entity.yml.permalink);
|
||||
entity.relative_url = path.join(env.base_path, entity.yml.permalink);
|
||||
|
||||
view = {
|
||||
page: entity.yml // data for just *this* page
|
||||
//, data: desi.data // data.yml
|
||||
// https://github.com/janl/mustache.js/issues/415
|
||||
, data: num2str(desi.data)
|
||||
, collection: {} // data for just *this* collection
|
||||
, categories: [] // *all* categories in all collections
|
||||
, tags: [] // *all* tags in all collections
|
||||
, site: num2str(desi.site || {})
|
||||
, url: entity.canonical_url
|
||||
, canonical_url: entity.canonical_url
|
||||
, relative_url: entity.relative_url
|
||||
, urls: desi.urls
|
||||
, previous: arr[i - 1]
|
||||
, next: arr[i + 1]
|
||||
, posts: { collated: desi.collated }
|
||||
// TODO concat theme, widget, and site assets
|
||||
, assets: desi.assets.join('\n')
|
||||
};
|
||||
// TODO nested names?
|
||||
navigation.forEach(function (nav) {
|
||||
nav.href = env.base_path + '/' + nav.name;
|
||||
nav.path = env.base_path + '/' + nav.name;
|
||||
|
||||
//console.log('rel:', view.relative_url);
|
||||
view.site.author = desi.data.author;
|
||||
view.site.navigation = JSON.parse(JSON.stringify(desi.navigation));
|
||||
view.site.navigation.forEach(function (nav) {
|
||||
|
||||
if (nav.href === view.relative_url) {
|
||||
// path.basename(nav.path, path.extname(nav.path))
|
||||
if (nav.href.replace(/(\/)?(\/index)?(\.html)?$/i, '') === entity.relative_url.replace(/(\/)?(\/index)?(\.html)?$/i, '')) {
|
||||
nav.active = true;
|
||||
}
|
||||
});
|
||||
// backwards compat
|
||||
view.site['navigation?to_pages'] = view.site.navigation;
|
||||
view.site['navigation?to__root'] = view.site.navigation;
|
||||
view.data.navigation = view.site.navigation;
|
||||
view.data['navigation?to_pages'] = view.site.navigation;
|
||||
view.data['navigation?to__root'] = view.site.navigation;
|
||||
|
||||
layers.forEach(function (current) {
|
||||
// TODO meta.layout
|
||||
var body = (current.body || current.contents || '').trim()
|
||||
, html
|
||||
, curview = {}
|
||||
;
|
||||
view = {
|
||||
env: env
|
||||
, config: desi.config
|
||||
, site: desi.site
|
||||
, data: desi.data
|
||||
, entity: entity
|
||||
, entity_index: i
|
||||
, entities: arr
|
||||
, desi: desi
|
||||
, navigation: navigation
|
||||
, author: num2str(author)
|
||||
};
|
||||
|
||||
// TODO move to normalization
|
||||
current.path = current.path || (entity.relativePath + '/' + entity.name);
|
||||
|
||||
if (/\.(html|htm)$/.test(current.path)) {
|
||||
html = body;
|
||||
} else if (/\.(md|markdown|mdown|mkdn|mkd|mdwn|mdtxt|mdtext)$/.test(current.ext)) {
|
||||
html = marked.render(body)
|
||||
//.replace('"', '"')
|
||||
//.replace(''', "'")
|
||||
//.replace('/', '/')
|
||||
;
|
||||
} else {
|
||||
console.error('unknown parser for ' + (entity.path));
|
||||
}
|
||||
|
||||
view.content = previous;
|
||||
view.page.content = previous;
|
||||
|
||||
// to prevent perfect object equality (and potential template caching)
|
||||
Object.keys(view).forEach(function (key) {
|
||||
curview[key] = view[key];
|
||||
});
|
||||
previous = Mustache.render(html, curview, desi.partials);
|
||||
desi.transforms.forEach(function (fn) {
|
||||
view = fn(view);
|
||||
});
|
||||
|
||||
// NOTE: by now, all permalinks should be in the format /path/to/page.html or /path/to/page/index.html
|
||||
if (/^(index)?(\/?index.html)?$/.test(entity.yml.permalink)) {
|
||||
console.info('found compiled index');
|
||||
compiled.push({ contents: previous, path: path.join(desi.config.compiled_path, 'index.html') });
|
||||
} else {
|
||||
compiled.push({ contents: previous, path: path.join(desi.config.compiled_path, entity.yml.permalink) });
|
||||
}
|
||||
return renderLayers(desi, env, view, entity).then(function (html) {
|
||||
// NOTE: by now, all permalinks should be in the format /path/to/page.html or /path/to/page/index.html
|
||||
if (/^(index)?(\/?index.html)?$/.test(entity.yml.permalink)) {
|
||||
console.info('found compiled index');
|
||||
compiled.push({ contents: html, path: path.join('index.html') });
|
||||
} else {
|
||||
compiled.push({ contents: html, path: path.join(entity.yml.permalink) });
|
||||
}
|
||||
|
||||
entity.yml.redirects = entity.yml.redirects || [];
|
||||
if (/\/index.html$/.test(entity.yml.permalink)) {
|
||||
entity.yml.redirects.push(entity.yml.permalink.replace(/\/index.html$/, '.html'));
|
||||
} else if (/\.html$/.test(entity.yml.permalink)) {
|
||||
entity.yml.redirects.push(entity.yml.permalink.replace(/\.html?$/, '/index.html'));
|
||||
} else {
|
||||
console.info('found index, ignoring redirect');
|
||||
}
|
||||
entity.yml.redirects.forEach(function (redirect) {
|
||||
var content
|
||||
;
|
||||
entity.yml.redirects = entity.yml.redirects || [];
|
||||
|
||||
// TODO move to partial
|
||||
content =
|
||||
'<html>'
|
||||
+ '<head>'
|
||||
+ '<title>Redirecting to ' + entity.yml.title + '</title>'
|
||||
+ '<meta http-equiv="refresh" content="0;URL=\''
|
||||
+ desi.urls.url + path.join(desi.urls.base_path, entity.yml.permalink)
|
||||
+ '\'" />'
|
||||
+ '</head>'
|
||||
+ '<body>'
|
||||
+ '<p>This page has moved to a <a href="'
|
||||
+ desi.urls.url + path.join(desi.urls.base_path, entity.yml.permalink)
|
||||
+'">'
|
||||
+ entity.yml.title
|
||||
+ '</a>.</p>'
|
||||
+ '</body>'
|
||||
+ '</html>'
|
||||
;
|
||||
if (/\/index.html$/.test(entity.yml.permalink)) {
|
||||
entity.yml.redirects.push(entity.yml.permalink.replace(/\/index.html$/, '.html'));
|
||||
} else if (/\.html$/.test(entity.yml.permalink)) {
|
||||
entity.yml.redirects.push(entity.yml.permalink.replace(/\.html?$/, '/index.html'));
|
||||
} else {
|
||||
console.info('found index, ignoring redirect');
|
||||
}
|
||||
|
||||
compiled.push({ contents: content, path: path.join(desi.config.compiled_path, redirect) });
|
||||
entity.yml.redirects.forEach(function (redirect) {
|
||||
var html = Mustache.render(desi.partials.redirect, view)
|
||||
;
|
||||
|
||||
compiled.push({
|
||||
contents: html
|
||||
, path: path.join(redirect)
|
||||
});
|
||||
});
|
||||
}).catch(function (e) {
|
||||
console.error('failing at build step here here here');
|
||||
throw e;
|
||||
if (env.onError) {
|
||||
return env.onError(e);
|
||||
} else {
|
||||
console.error("couldn't render " + entity.path);
|
||||
console.error(entity);
|
||||
console.error(e);
|
||||
throw e;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function doStuff() {
|
||||
var themes = desi.content.themes.filter(function (f) { return !/\blayouts\b/.test(f.path); })
|
||||
;
|
||||
|
||||
console.info('[first] compiling theme assets');
|
||||
desi.content.themes.filter(function (f) { return !/\blayouts\b/.test(f.path); }).forEach(compileThemeEntity);
|
||||
|
||||
console.info('compiling root pages');
|
||||
desi.content.root.forEach(compileContentEntity);
|
||||
console.info('compiling article pages');
|
||||
desi.content.collections.forEach(compileContentEntity);
|
||||
|
||||
desi.compiled = compiled;
|
||||
return PromiseA.resolve(desi);
|
||||
return forEachAsync(themes, compileThemeEntity).then(function () {
|
||||
console.info('compiling root pages');
|
||||
return forEachAsync(desi.content.root, compileContentEntity).then(function () {
|
||||
console.info('compiling article pages');
|
||||
desi.content.collections.forEach(compileContentEntity);
|
||||
}).then(function () {
|
||||
desi.compiled = compiled;
|
||||
return desi;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (!desi.partials) {
|
||||
return fsapi.getAllPartials().then(doStuff);
|
||||
return fsapi.getAllPartials().then(function (partials) {
|
||||
if (partials.error) {
|
||||
throw partials.error;
|
||||
}
|
||||
|
||||
desi.partials = partials;
|
||||
return doStuff();
|
||||
});
|
||||
} else {
|
||||
return doStuff();
|
||||
}
|
||||
};
|
||||
|
||||
Desi.save = function (desi) {
|
||||
Desi.buildAll = function (desi, env) {
|
||||
return Desi.getDirtyFiles(desi, env.since)
|
||||
.then(Desi.parseFrontmatter)
|
||||
.then(Desi.getNav)
|
||||
.then(Desi.normalizeYml)
|
||||
.then(function () {
|
||||
Desi.collate(desi, env)
|
||||
})
|
||||
.then(function () {
|
||||
return Desi.build(desi, env);
|
||||
}).then(function () {
|
||||
return Desi.copyAssets(desi, env);
|
||||
}).catch(function (e) {
|
||||
if (env.onError) {
|
||||
return env.onError(e);
|
||||
} else {
|
||||
console.error('buildAll failed somewhere');
|
||||
console.error(e);
|
||||
throw e;
|
||||
}
|
||||
})
|
||||
;
|
||||
};
|
||||
|
||||
Desi.write = function (desi, env) {
|
||||
var compiled = desi.compiled.slice(0)
|
||||
, batches = []
|
||||
, now
|
||||
|
@ -868,6 +1061,10 @@
|
|||
return;
|
||||
}
|
||||
|
||||
compiled.forEach(function (thing) {
|
||||
thing.path = path.join(env.compiled_path, thing.path);
|
||||
});
|
||||
|
||||
// because some servers / proxies are terrible at handling large uploads (>= 100k)
|
||||
// (vagrant? or express? one of the two is CRAZY slow)
|
||||
console.info('saving compiled files', desi.compiled);
|
||||
|
|
|
@ -0,0 +1,137 @@
|
|||
---
|
||||
amazon_link_enhancer: |
|
||||
<!-- amazon -->
|
||||
<script async="true" type="text/javascript" src="http://wms.assoc-amazon.com/20070822/US/js/link-enhancer-common.js?tag={{ amazon_affiliate_id }}">
|
||||
</script>
|
||||
<noscript>
|
||||
<img src="http://wms.assoc-amazon.com/20070822/US/img/noscript.gif?tag={{ amazon_affiliate_id }}" alt="" />
|
||||
</noscript>
|
||||
|
||||
google_analytics: |
|
||||
<script type="text/javascript">
|
||||
|
||||
var _gaq = _gaq || [];
|
||||
_gaq.push(['_setAccount', '{{ google_analytics.tracking_id }}']);
|
||||
_gaq.push(['_trackPageview']);
|
||||
|
||||
(function() {
|
||||
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
|
||||
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
||||
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
|
||||
})();
|
||||
|
||||
</script>
|
||||
|
||||
disqus: |
|
||||
<div id="disqus_thread"></div>
|
||||
<script type="text/javascript">
|
||||
/* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */
|
||||
var disqus_shortname = '{{ disqus.shortname }}'; // required: replace example with your forum shortname
|
||||
var disqus_identifier = '{{ disqus.identifier }}' || undefined;
|
||||
var disqus_url = '{{{ disqus.url }}}' || undefined;
|
||||
|
||||
/* * * DON'T EDIT BELOW THIS LINE * * */
|
||||
(function() {
|
||||
var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
|
||||
dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js';
|
||||
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
|
||||
})();
|
||||
</script>
|
||||
<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>
|
||||
|
||||
redirect: >
|
||||
<html>
|
||||
<head>
|
||||
<title>Redirecting to {{ entity.title }}</title>
|
||||
<meta http-equiv="refresh" content="0;URL='{{{ env.url }}}{{{ entity.permalink }}}'"/>
|
||||
</head>
|
||||
<body>
|
||||
<p>This page has moved to
|
||||
<a href="{{{ env.url }}}{{{ entity.permalink }}}">{{ entity.title }}</a>.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
pages_list: >
|
||||
<li{{# active }} class="active"{{/ active }}><a{{# active }} class="active"{{/ active }}
|
||||
href="{{{ path }}}"
|
||||
>{{ title }}</a></li>
|
||||
|
||||
# [{ 'year': year,
|
||||
# 'months' : [{ 'month' : month,
|
||||
# 'pages': [{}, {}, ..] }, ..] }, ..]
|
||||
posts_collate: |
|
||||
{{# years }}
|
||||
<h2>{{ year }}</h2>
|
||||
{{> posts_collate_year }}
|
||||
{{/ years }}
|
||||
|
||||
posts_collate_year: |
|
||||
{{# months }}
|
||||
<h3>{{ month }}</h3>
|
||||
{{> posts_collate_month }}
|
||||
{{/ months }}
|
||||
|
||||
posts_collate_month: |
|
||||
<ul>
|
||||
{{# pages }}
|
||||
{{> posts_collate_pages }}
|
||||
{{/ pages }}
|
||||
</ul>
|
||||
|
||||
posts_collate_pages: |
|
||||
<li><span>{{ year }}-{{ month }}-{{ day }}</span> »
|
||||
<a href="{{{url}}}"
|
||||
>{{ title }}</a></li>
|
||||
|
||||
google_prettify: |
|
||||
<script src="http://cdnjs.cloudflare.com/ajax/libs/prettify/188.0.0/prettify.js"></script>
|
||||
<script>
|
||||
var pres = document.getElementsByTagName("pre");
|
||||
for (var i=0; i < pres.length; ++i) {
|
||||
pres[i].className = "prettyprint {{#linenums}}linenums{{/linenums}}";
|
||||
}
|
||||
prettyPrint();
|
||||
</script>
|
||||
<!-- end Google Prettify -->
|
||||
|
||||
google_ads: |
|
||||
<script type="text/javascript">
|
||||
|
||||
var _gaq = _gaq || [];
|
||||
_gaq.push(['_setAccount', {{#id}}'{{.}}'{{/id}}]);
|
||||
_gaq.push(['_trackPageview']);
|
||||
|
||||
(function() {
|
||||
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
|
||||
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
||||
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
|
||||
})();
|
||||
|
||||
</script>
|
||||
|
||||
facebook_connect: |
|
||||
<!-- facebook -->
|
||||
<div id="fb-root"></div>
|
||||
<script>(function(d, s, id) {
|
||||
var js, fjs = d.getElementsByTagName(s)[0];
|
||||
if (d.getElementById(id)) return;
|
||||
js = d.createElement(s); js.id = id; js.async=true;
|
||||
js.src = "//connect.facebook.net/en_US/all.js#xfbml=1&appId=213439508797174";
|
||||
fjs.parentNode.insertBefore(js, fjs);
|
||||
}(document, 'script', 'facebook-jssdk'));</script>
|
||||
|
||||
google_plusone: |
|
||||
<!-- g+ -->
|
||||
<!-- Place this tag after the last +1 button tag. -->
|
||||
<script type="text/javascript">
|
||||
(function() {
|
||||
var po = document.createElement('script'); po.type = 'text/javascript'; po.async = true;
|
||||
po.src = 'https://apis.google.com/js/plusone.js';
|
||||
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(po, s);
|
||||
})();
|
||||
</script>
|
||||
|
||||
twitter: |
|
||||
<!-- twitter -->
|
||||
<script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0];if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.async=true;js.src="//platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");</script>
|
|
@ -213,7 +213,6 @@
|
|||
return request.post('/api/fs/walk?_method=GET' + dotfiles + extensions + contents + sha1sum, {
|
||||
dirs: collections
|
||||
}).then(function (resp) {
|
||||
console.log(collections);
|
||||
return JSON.parse(resp);
|
||||
});
|
||||
};
|
||||
|
@ -252,14 +251,20 @@
|
|||
, data = {}
|
||||
;
|
||||
|
||||
if (file.error) {
|
||||
console.error(file);
|
||||
console.error(file.error);
|
||||
return;
|
||||
}
|
||||
|
||||
if (/\.(ya?ml)$/i.test(file.name)) {
|
||||
console.log();
|
||||
try {
|
||||
data = exports.YAML.parse(file.contents) || {};
|
||||
if ("undefined" === obj[keyname][filename]) {
|
||||
if ("undefined" === data) {
|
||||
data = {};
|
||||
}
|
||||
} catch(e) {
|
||||
data = { error: e };
|
||||
console.error("Could not parse yaml for " + filename);
|
||||
console.error(file);
|
||||
console.error(e);
|
||||
|
@ -269,6 +274,7 @@
|
|||
try {
|
||||
data = JSON.parse(file.contents) || {};
|
||||
} catch(e) {
|
||||
data = { error: e };
|
||||
console.error("Could not parse json for " + filename);
|
||||
console.error(file);
|
||||
console.error(e);
|
||||
|
@ -278,7 +284,7 @@
|
|||
console.error(file);
|
||||
}
|
||||
|
||||
obj[keyname][filename] = data;
|
||||
obj[keyname][filename] = data || obj[keyname][filename];
|
||||
/*
|
||||
if (!obj[keyname][filename]) {
|
||||
obj[keyname][filename] = {};
|
||||
|
@ -300,15 +306,20 @@
|
|||
;
|
||||
|
||||
Object.keys(results.partials).forEach(function (key) {
|
||||
var partial = partials[key];
|
||||
var partial = results.partials[key]
|
||||
;
|
||||
|
||||
Object.keys(partial).forEach(function (prop) {
|
||||
if (partials[prop]) {
|
||||
console.warn('partial \'' + prop + '\' overwritten by ' + key);
|
||||
}
|
||||
|
||||
partials[prop] = partial[prop];
|
||||
});
|
||||
});
|
||||
|
||||
console.info('getAllPartialts', results);
|
||||
console.info(partials);
|
||||
return partials;
|
||||
});
|
||||
};
|
||||
|
|
58
partials.yml
58
partials.yml
|
@ -1,58 +0,0 @@
|
|||
---
|
||||
pages_list: >
|
||||
<li{{# active }} class="active"{{/ active }}><a{{# active }} class="active"{{/ active }}
|
||||
href="{{{ path }}}"
|
||||
>{{ title }}</a></li>
|
||||
|
||||
# [{ 'year': year,
|
||||
# 'months' : [{ 'month' : month,
|
||||
# 'pages': [{}, {}, ..] }, ..] }, ..]
|
||||
posts_collate: |
|
||||
{{# years }}
|
||||
<h2>{{ year }}</h2>
|
||||
{{> posts_collate_year }}
|
||||
{{/ years }}
|
||||
|
||||
posts_collate_year: |
|
||||
{{# months }}
|
||||
<h3>{{ month }}</h3>
|
||||
{{> posts_collate_month }}
|
||||
{{/ months }}
|
||||
|
||||
posts_collate_month: |
|
||||
<ul>
|
||||
{{# pages }}
|
||||
{{> posts_collate_pages }}
|
||||
{{/ pages }}
|
||||
</ul>
|
||||
|
||||
posts_collate_pages: |
|
||||
<li><span>{{ year }}-{{ month }}-{{ day }}</span> »
|
||||
<a href="{{{url}}}"
|
||||
>{{ title }}</a></li>
|
||||
|
||||
google_prettify: |
|
||||
<script src="http://cdnjs.cloudflare.com/ajax/libs/prettify/188.0.0/prettify.js"></script>
|
||||
<script>
|
||||
var pres = document.getElementsByTagName("pre");
|
||||
for (var i=0; i < pres.length; ++i) {
|
||||
pres[i].className = "prettyprint {{#linenums}}linenums{{/linenums}}";
|
||||
}
|
||||
prettyPrint();
|
||||
</script>
|
||||
<!-- end Google Prettify -->
|
||||
|
||||
google_ads: |
|
||||
<script type="text/javascript">
|
||||
|
||||
var _gaq = _gaq || [];
|
||||
_gaq.push(['_setAccount', {{#id}}'{{.}}'{{/id}}]);
|
||||
_gaq.push(['_trackPageview']);
|
||||
|
||||
(function() {
|
||||
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
|
||||
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
||||
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
|
||||
})();
|
||||
|
||||
</script>
|
|
@ -11,14 +11,14 @@ angular.module('myApp.build', ['ngRoute'])
|
|||
|
||||
.controller('BuildCtrl'
|
||||
, ['$scope', '$location', '$timeout', 'Desirae'
|
||||
, function ($scope, $location, $timeout, Desirae) {
|
||||
, function ($scope, $location, $timeout, DesiraeService) {
|
||||
var scope = this
|
||||
, path = window.path
|
||||
;
|
||||
|
||||
function init() {
|
||||
console.log('desi loading');
|
||||
Desirae.meta().then(function (desi) {
|
||||
DesiraeService.meta().then(function (desi) {
|
||||
scope.blogdir = desi.blogdir.path.replace(/^\/(Users|home)\/[^\/]+\//, '~/');
|
||||
scope.site = desi.site;
|
||||
|
||||
|
@ -40,108 +40,50 @@ angular.module('myApp.build', ['ngRoute'])
|
|||
scope.extensions = ['md', 'html'];
|
||||
}
|
||||
|
||||
scope.onChange = function () {
|
||||
var post = scope.selected.post
|
||||
, selected = scope.selected
|
||||
;
|
||||
|
||||
post.yml.title = post.yml.title || '';
|
||||
post.yml.description = post.yml.description || '';
|
||||
|
||||
if (selected.permalink === post.yml.permalink) {
|
||||
selected.permalink = '/articles/' + post.yml.title.toLowerCase()
|
||||
.replace(/["']/g, '')
|
||||
.replace(/\W/g, '-')
|
||||
.replace(/^-+/g, '')
|
||||
.replace(/-+$/g, '')
|
||||
.replace(/--/g, '-')
|
||||
+ '.' + selected.format
|
||||
;
|
||||
|
||||
post.yml.permalink = selected.permalink;
|
||||
}
|
||||
if (window.path.extname(post.yml.permalink) !== '.' + selected.format) {
|
||||
post.yml.permalink = post.yml.permalink.replace(/\.\w+$/, '.' + selected.format);
|
||||
}
|
||||
|
||||
post.frontmatter = window.jsyaml.dump(post.yml).trim();
|
||||
|
||||
// TODO use some sort of filepath pattern in config.yml
|
||||
selected.path = window.path.join((selected.collection || 'posts'), window.path.basename(post.yml.permalink));
|
||||
selected.abspath = window.path.join(scope.blogdir, selected.path);
|
||||
};
|
||||
scope.onFrontmatterChange = function () {
|
||||
var data
|
||||
;
|
||||
|
||||
try {
|
||||
if (!scope.selected.post.frontmatter || !scope.selected.post.frontmatter.trim()) {
|
||||
throw new Error('deleted frontmatter');
|
||||
}
|
||||
data = window.jsyaml.load(scope.selected.post.frontmatter);
|
||||
scope.selected.format = data.permalink.replace(/.*\.(\w+$)/, '$1');
|
||||
if (!data.permalink) {
|
||||
data = scope.selected.permalink;
|
||||
}
|
||||
scope.selected.post.yml = data;
|
||||
} catch(e) {
|
||||
console.error(e);
|
||||
console.error('ignoring update that created parse error');
|
||||
scope.selected.post.frontmatter = window.jsyaml.dump(scope.selected.post.yml).trim();
|
||||
scope.onError = function (e) {
|
||||
console.error(e);
|
||||
if (window.confirm("Encountered an error. Please inspect the console.\n\nWould you like to ignore the error and continue?")) {
|
||||
return window.Promise.resolve();
|
||||
} else {
|
||||
return window.Promise.reject();
|
||||
}
|
||||
};
|
||||
|
||||
function updateDate() {
|
||||
$timeout.cancel(scope.dtlock);
|
||||
scope.dtlock = $timeout(function () {
|
||||
if (scope.selected && scope.selected.date === scope.selected.post.yml.date) {
|
||||
scope.selected.date = scope.selected.post.yml.date = Desirae.toDesiDate(new Date());
|
||||
}
|
||||
scope.onChange();
|
||||
updateDate();
|
||||
}, 60 * 1000);
|
||||
}
|
||||
|
||||
scope.upsert = function () {
|
||||
console.log('upserted');
|
||||
if (-1 === scope.extensions.indexOf(scope.selected.format)) {
|
||||
window.alert('.' + scope.selected.format + ' is not a supported extension.\n\nPlease choose from: .' + scope.extensions.join(' .'));
|
||||
return;
|
||||
}
|
||||
|
||||
scope.selected.post.yml.uuid = scope.selected.uuid;
|
||||
['updated', 'theme', 'layout', 'swatch'].forEach(function (key) {
|
||||
if (!scope.selected.post.yml[key]) {
|
||||
delete scope.selected.post.yml[key];
|
||||
}
|
||||
});
|
||||
scope.onChange();
|
||||
|
||||
var files = []
|
||||
scope.buildOne = function (envstr) {
|
||||
var env
|
||||
;
|
||||
|
||||
files.push({
|
||||
path: scope.selected.path
|
||||
, contents:
|
||||
'---\n'
|
||||
+ scope.selected.post.frontmatter.trim()
|
||||
+ '\n'
|
||||
+ '---\n'
|
||||
+ '\n'
|
||||
+ scope.selected.post.body.trim()
|
||||
});
|
||||
// TODO is there a legitimate case where in addition to base_path (root of the blog)
|
||||
// a user would need owner_base? i.e. school.edu/~/rogers/blog school.edu/~/rogers/assets
|
||||
if ('production' === envstr) {
|
||||
env = {
|
||||
url: scope.production_url
|
||||
, base_url: scope.development_url.replace(/(https?:\/\/[^\/#?]+)/, '$1')
|
||||
, compiled_path: 'compiled'
|
||||
, since: 0
|
||||
, onError: scope.onError
|
||||
};
|
||||
} else {
|
||||
env = {
|
||||
url: scope.development_url
|
||||
, base_url: scope.development_url.replace(/(https?:\/\/[^\/#?]+)/, '$1')
|
||||
, base_path: scope.development_url.replace(/https?:\/\/[^\/#?]+/, '')
|
||||
, compiled_path: 'compiled_dev'
|
||||
, since: 0
|
||||
, onError: scope.onError
|
||||
};
|
||||
}
|
||||
|
||||
console.log(files);
|
||||
Desirae.putFiles(files).then(function (results) {
|
||||
console.log('TODO check for error');
|
||||
console.log(results);
|
||||
$location.path('/build');
|
||||
}).catch(function (e) {
|
||||
$timeout.cancel(scope.dtlock);
|
||||
console.error(scope.site);
|
||||
console.error(e);
|
||||
window.alert("Error Nation! :/");
|
||||
throw e;
|
||||
return DesiraeService.build(env).then(function () {
|
||||
DesiraeService.write(env);
|
||||
});
|
||||
};
|
||||
|
||||
scope.build = function (envs) {
|
||||
window.forEachAsync(envs, function (env) {
|
||||
return scope.buildOne(env);
|
||||
}).then(function () {
|
||||
window.alert('Build(s) Complete');
|
||||
});
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue