make Prettier

This commit is contained in:
AJ ONeal 2020-11-08 20:30:15 -07:00
parent 416484db42
commit ff74030e52
31 changed files with 1958 additions and 1403 deletions

1
.prettierrc.json Normal file
View File

@ -0,0 +1 @@
{}

View File

@ -5,23 +5,20 @@ Not a Web Developer?
You're in the wrong place. **Go to <http://dear.desi>** and follow the instructions there. You're in the wrong place. **Go to <http://dear.desi>** and follow the instructions there.
--> -->
Did you mean to come here? # Did you mean to come here?
==========================
If you're a normal person interested in *Desi, the DIY blog platform for normal people*, If you're a normal person interested in _Desi, the DIY blog platform for normal people_,
you might have meant to go to [DearDesi](http://dear.desi) instead. you might have meant to go to [DearDesi](http://dear.desi) instead.
Otherwise, if you're a cyborg, wizzard, or web developer: carry on. Otherwise, if you're a cyborg, wizzard, or web developer: carry on.
Dear Desi # Dear Desi
=========
These instructions cover the command line only. These instructions cover the command line only.
If you want instructions for the web interface, head over to [DearDesi](http://dear.desi). If you want instructions for the web interface, head over to [DearDesi](http://dear.desi).
Command Line Install (for developers) ## Command Line Install (for developers)
--------------------
This assumes that you already have `git` and `node` installed, This assumes that you already have `git` and `node` installed,
otherwise see [node-installer.sh](https://git.coolaj86.com/coolaj86/node-installer.sh) otherwise see [node-installer.sh](https://git.coolaj86.com/coolaj86/node-installer.sh)
@ -36,22 +33,20 @@ npm install -g desi
That was easy That was easy
Quick Usage ## Quick Usage
-------
* desi init -d ~/Desktop/new-blog - desi init -d ~/Desktop/new-blog
* pushd ~/Desktop/new-blog - pushd ~/Desktop/new-blog
* desi post "my first post" - desi post "my first post"
* desi build - desi build
* desi serve - desi serve
<http://local.dear.desi:65080> <http://local.dear.desi:65080>
**Note**: both through command line and web you need `site.yml` and `authors/xyz.yml` configured in order to create a post (as well as build). **Note**: both through command line and web you need `site.yml` and `authors/xyz.yml` configured in order to create a post (as well as build).
The post commands output the location of post in various formats. The post commands output the location of post in various formats.
Initialize your blog (step 1) ## Initialize your blog (step 1)
--------
You can do this 3 ways: You can do this 3 ways:
@ -98,34 +93,37 @@ Obviously this is a little different for everyone, so here's what I'd recommend:
1. start by following the Automated procedure above 1. start by following the Automated procedure above
2. copy over your posts/articles folder(s) 2. copy over your posts/articles folder(s)
3. edit `config.yml` to add a config with a permalink with your collections (posts, articles, essays, whatever you call them) 3. edit `config.yml` to add a config with a permalink with your collections (posts, articles, essays, whatever you call them)
4. skip ahead to the *Setup your blog* section and make sure your `site.yml` and `authors/xxx.yml` are correct. 4. skip ahead to the _Setup your blog_ section and make sure your `site.yml` and `authors/xxx.yml` are correct.
5. run `desi build -d /path/to/blog` to test if there are any issues with your existing yaml 5. run `desi build -d /path/to/blog` to test if there are any issues with your existing yaml
* if there are, you can take a look at the [normalize](https://github.com/DearDesi/desirae/blob/master/lib/transform-core.js#L72) function and perhaps hand-edit a few things (and when you're ready, you can [register your transform](https://github.com/DearDesi/deardesi/blob/master/bin/deardesi.js#L28) for collections.
- if there are, you can take a look at the [normalize](https://github.com/DearDesi/desirae/blob/master/lib/transform-core.js#L72) function and perhaps hand-edit a few things (and when you're ready, you can [register your transform](https://github.com/DearDesi/deardesi/blob/master/bin/deardesi.js#L28) for collections.
6. Now copy over your theme and set it to be the default in `site.yml` 6. Now copy over your theme and set it to be the default in `site.yml`
7. build again. Your site probably won't look right: 7. build again. Your site probably won't look right:
* look for stuff like `urls.base_url`, `host`, `page.url` that might have an extra `/` at the beginning or end or be named slightly differently.
- look for stuff like `urls.base_url`, `host`, `page.url` that might have an extra `/` at the beginning or end or be named slightly differently.
See <https://github.com/DearDesi/desirae/blob/master/GLOSSARY.md> for disambiguation about the meaning of terms in Desi. See <https://github.com/DearDesi/desirae/blob/master/GLOSSARY.md> for disambiguation about the meaning of terms in Desi.
Setup your blog (step 2) ## Setup your blog (step 2)
------------
1. Create an authors file in `authors/YOUR_NAME.yml` and model it after [this example](https://github.com/DearDesi/deardesi/blob/master/example/authors/johndoe.yml) 1. Create an authors file in `authors/YOUR_NAME.yml` and model it after [this example](https://github.com/DearDesi/deardesi/blob/master/example/authors/johndoe.yml)
* You don't need to use all of the fields (your template might not even support them all)
- You don't need to use all of the fields (your template might not even support them all)
2. Create a site file as `site.yml`, similar to [this example](https://github.com/DearDesi/deardesi/blob/master/example/site.yml) 2. Create a site file as `site.yml`, similar to [this example](https://github.com/DearDesi/deardesi/blob/master/example/site.yml)
**Important Things** **Important Things**
* `site.yml.base_url` - the point of ownership (usually blog.example.com or example.com) - `site.yml.base_url` - the point of ownership (usually blog.example.com or example.com)
* `site.yml.base_path` - where the blog is "mounted", relative to the `base_url` (usually `/` or `/blog`) - `site.yml.base_path` - where the blog is "mounted", relative to the `base_url` (usually `/` or `/blog`)
* `authors/me.yml.name` - most templates use this - `authors/me.yml.name` - most templates use this
* `authors/me.yml.email` - and this - `authors/me.yml.email` - and this
* `authors/me.yml.twitter` - and this - `authors/me.yml.twitter` - and this
Build your blog (step 2) ## Build your blog (step 2)
------------
The build *will* fail if you don't have `site.yml` and `authors/johndoe.yml` configured. The build _will_ fail if you don't have `site.yml` and `authors/johndoe.yml` configured.
```bash ```bash
desi build -d /path/to/blog desi build -d /path/to/blog

34
app.js
View File

@ -1,17 +1,21 @@
'use strict'; "use strict";
// Declare app level module which depends on views, and components // Declare app level module which depends on views, and components
angular.module('myApp', [ angular
'ngRoute', .module("myApp", [
'myApp.about', "ngRoute",
'myApp.authors', "myApp.about",
'myApp.site', "myApp.authors",
'myApp.build', "myApp.site",
'myApp.configure', "myApp.build",
'myApp.post', "myApp.configure",
'myApp.version', "myApp.post",
'myApp.services' "myApp.version",
]). "myApp.services",
config(['$routeProvider', function ($routeProvider) { ])
$routeProvider.otherwise({redirectTo: '/about'}); .config([
}]); "$routeProvider",
function ($routeProvider) {
$routeProvider.otherwise({ redirectTo: "/about" });
},
]);

View File

@ -1,157 +1,183 @@
#!/usr/bin/env node #!/usr/bin/env node
'use strict'; "use strict";
var PromiseA = require('bluebird') var PromiseA = require("bluebird"),
, fs = PromiseA.promisifyAll(require('fs')) fs = PromiseA.promisifyAll(require("fs")),
, fsx = PromiseA.promisifyAll(require('fs.extra')) fsx = PromiseA.promisifyAll(require("fs.extra")),
, tar = require('tar') tar = require("tar"),
//, requestAsync = PromiseA.promisify(require('request')) //, requestAsync = PromiseA.promisify(require('request'))
, request = PromiseA.promisifyAll(require('request')) request = PromiseA.promisifyAll(require("request")),
, forEachAsync = require('foreachasync').forEachAsync forEachAsync = require("foreachasync").forEachAsync,
//, spawn = require('child_process').spawn //, spawn = require('child_process').spawn
, path = require('path') path = require("path"),
, cli = require('cli') cli = require("cli"),
, UUID = require('node-uuid') UUID = require("node-uuid"),
, Desi Desi,
, zlib = require('zlib') zlib = require("zlib");
;
cli.parse({ cli.parse({
blogdir: ['d', 'Where your blog is, i.e. ~/path/to/blog', 'string', './'] blogdir: ["d", "Where your blog is, i.e. ~/path/to/blog", "string", "./"],
//, output: ['o', 'name of output directory within ~/path/to/blog', 'string', './compiled'] //, output: ['o', 'name of output directory within ~/path/to/blog', 'string', './compiled']
}); });
function init() { function init() {
Desi = require('desirae').Desirae; Desi = require("desirae").Desirae;
// //
// 1. Transform (yml, slug, etc) // 1. Transform (yml, slug, etc)
// //
Desi.registerTransform( Desi.registerTransform(
'lint' "lint",
, require('desirae/lib/transform-core').DesiraeTransformCore.lint require("desirae/lib/transform-core").DesiraeTransformCore.lint,
, { collections: true } { collections: true }
); );
Desi.registerTransform( Desi.registerTransform(
'root' "root",
, require('desirae/lib/transform-core').DesiraeTransformCore.root require("desirae/lib/transform-core").DesiraeTransformCore.root,
, { root: true } { root: true }
); );
Desi.registerTransform( Desi.registerTransform(
'normalize' "normalize",
, require('desirae/lib/transform-core').DesiraeTransformCore.normalize require("desirae/lib/transform-core").DesiraeTransformCore.normalize,
, { root: true, collections: true } { root: true, collections: true }
); );
Desi.registerTransform( Desi.registerTransform(
'disqus' "disqus",
, require('desirae/lib/transform-core').DesiraeTransformCore.disqus require("desirae/lib/transform-core").DesiraeTransformCore.disqus,
, { collections: true } { collections: true }
); );
// //
// 2. Aggregate (rss, categories, tags, etc) // 2. Aggregate (rss, categories, tags, etc)
// //
Desi.registerAggregator(require('desirae/lib/aggregate-core').DesiraeAggregateCore.collate); Desi.registerAggregator(
require("desirae/lib/aggregate-core").DesiraeAggregateCore.collate
);
// //
// 3. Datamap (ruhoh, desirae, jade, mustache, liquid) // 3. Datamap (ruhoh, desirae, jade, mustache, liquid)
// //
Desi.registerDataMapper('desirae', require('desirae/lib/datamap-core').DesiraeDatamapCore); Desi.registerDataMapper(
Desi.registerDataMapper('desirae@1.0', require('desirae/lib/datamap-core').DesiraeDatamapCore); "desirae",
require("desirae/lib/datamap-core").DesiraeDatamapCore
);
Desi.registerDataMapper(
"desirae@1.0",
require("desirae/lib/datamap-core").DesiraeDatamapCore
);
// TODO ruhoh versions are ruhoh-twitter (1.0) and ruhoh-boostrap-2 (2.6) // TODO ruhoh versions are ruhoh-twitter (1.0) and ruhoh-boostrap-2 (2.6)
Desi.registerDataMapper('ruhoh', require('desirae-datamap-ruhoh').DesiraeDatamapRuhoh); Desi.registerDataMapper(
Desi.registerDataMapper('ruhoh@1.0', require('desirae-datamap-ruhoh').DesiraeDatamapRuhoh); "ruhoh",
Desi.registerDataMapper('ruhoh@2.6', require('desirae-datamap-ruhoh').DesiraeDatamapRuhoh); require("desirae-datamap-ruhoh").DesiraeDatamapRuhoh
);
Desi.registerDataMapper(
"ruhoh@1.0",
require("desirae-datamap-ruhoh").DesiraeDatamapRuhoh
);
Desi.registerDataMapper(
"ruhoh@2.6",
require("desirae-datamap-ruhoh").DesiraeDatamapRuhoh
);
// //
// 4. Render (md -> html, less -> css, etc) // 4. Render (md -> html, less -> css, etc)
// //
Desi.registerRenderer( Desi.registerRenderer(
'js' "js",
, require('desirae/lib/render-core').DesiraeRenderJs require("desirae/lib/render-core").DesiraeRenderJs,
, { themes: true, assets: true } { themes: true, assets: true }
); );
Desi.registerRenderer( Desi.registerRenderer(
'css' "css",
, require('desirae/lib/render-core').DesiraeRenderCss require("desirae/lib/render-core").DesiraeRenderCss,
, { themes: true, assets: true } { themes: true, assets: true }
); );
['html', 'htm', 'xhtm', 'xhtml'].forEach(function (ext) { ["html", "htm", "xhtm", "xhtml"].forEach(function (ext) {
Desi.registerRenderer( Desi.registerRenderer(
ext ext,
, require('desirae/lib/render-core').DesiraeRenderHtml require("desirae/lib/render-core").DesiraeRenderHtml,
, { root: true, collections: true, themes: true, assets: true } { root: true, collections: true, themes: true, assets: true }
); );
}); });
['md', 'markdown', 'mdown', 'mkdn', 'mkd', 'mdwn', 'mdtxt', 'mdtext'].forEach(function (ext) { ["md", "markdown", "mdown", "mkdn", "mkd", "mdwn", "mdtxt", "mdtext"].forEach(
Desi.registerRenderer( function (ext) {
ext Desi.registerRenderer(
, require('desirae/lib/render-core').DesiraeRenderMarkdown ext,
, { root: true, collections: true } require("desirae/lib/render-core").DesiraeRenderMarkdown,
); { root: true, collections: true }
}); );
}
);
Desi.registerRenderer( Desi.registerRenderer(
'jade' "jade",
, require('desirae/lib/render-core').DesiraeRenderJade require("desirae/lib/render-core").DesiraeRenderJade,
// TODO how to support jade in place of Mustache for layouts? // TODO how to support jade in place of Mustache for layouts?
, { root: true, collections: true, themes: true } { root: true, collections: true, themes: true }
); );
} }
function serve(displayDir, blogdir) { function serve(displayDir, blogdir) {
var http = require('http') var http = require("http"),
//, https = require('https') //, https = require('https')
, app = require('../server').create({ blogdir: blogdir }) app = require("../server").create({ blogdir: blogdir }),
, server server;
;
server = http.createServer(app).listen(65080, function () { server = http
console.info("Listening from " + displayDir); .createServer(app)
console.info("Listening on http://local.dear.desi:" + server.address().port); .listen(65080, function () {
}).on('error', function (err) { console.info("Listening from " + displayDir);
if (/EADDRINUSE/.test(err.message)) { console.info(
console.error(""); "Listening on http://local.dear.desi:" + server.address().port
console.error("You're already running desi in another tab."); );
console.error(""); })
console.error("Go to the other tab and press <control> + c to stop her. Then you can come back here to try again."); .on("error", function (err) {
console.error(""); if (/EADDRINUSE/.test(err.message)) {
console.error(""); console.error("");
return; console.error("You're already running desi in another tab.");
} console.error("");
console.error(
"Go to the other tab and press <control> + c to stop her. Then you can come back here to try again."
);
console.error("");
console.error("");
return;
}
throw err; throw err;
}); });
//secureServer = https.createServer(app).listen(65043); //secureServer = https.createServer(app).listen(65043);
} }
function build(blogdir) { function build(blogdir) {
var desi = {} var desi = {},
, env = {} env = {};
;
env.working_path = env.blogdir = blogdir; env.working_path = env.blogdir = blogdir;
Desi.init(desi, env).then(function () { Desi.init(desi, env).then(function () {
env.url = desi.site.base_url + desi.site.base_path.replace(/^\/$/, ''); env.url = desi.site.base_url + desi.site.base_path.replace(/^\/$/, "");
env.base_url = desi.site.base_url; env.base_url = desi.site.base_url;
env.base_path = desi.site.base_path; env.base_path = desi.site.base_path;
env.compiled_path = 'compiled'; env.compiled_path = "compiled";
//env.since = 0; //env.since = 0;
Desi.buildAll(desi, env).then(function () { Desi.buildAll(desi, env).then(function () {
Desi.write(desi, env).then(function (info) { Desi.write(desi, env).then(function (info) {
console.info( console.info(
'wrote', info.numFiles "wrote",
, 'files' info.numFiles,
, '(' + (info.size && (info.size / (1024 * 1024)).toFixed(2) || 'unkown'), 'MiB)' "files",
, 'in' "(" +
, ((info.end - info.start) / 1000).toFixed(3) + 's' ((info.size && (info.size / (1024 * 1024)).toFixed(2)) || "unkown"),
"MiB)",
"in",
((info.end - info.start) / 1000).toFixed(3) + "s"
); );
console.info('Built and saved to ' + path.join(env.working_path, env.compiled_path)); console.info(
"Built and saved to " + path.join(env.working_path, env.compiled_path)
);
}); });
}); });
}); });
@ -159,34 +185,33 @@ function build(blogdir) {
function createPost(originalDir, blogdir, title, extra) { function createPost(originalDir, blogdir, title, extra) {
if (!title) { if (!title) {
console.error("Usage desi post \"My First Post\""); console.error('Usage desi post "My First Post"');
console.error("(you didn't specify a title)"); console.error("(you didn't specify a title)");
process.exit(1); process.exit(1);
} }
if (extra) { if (extra) {
console.error("Usage desi post \"My First Post\""); console.error('Usage desi post "My First Post"');
console.error("(too many arguments - maybe you didn't put your title in quotes?)"); console.error(
"(too many arguments - maybe you didn't put your title in quotes?)"
);
process.exit(1); process.exit(1);
} }
var desi = {} var desi = {},
, env = {} env = {},
, post = {} post = {},
, slug slug,
, filepath filepath,
, displaypath displaypath;
;
env.working_path = env.blogdir = blogdir; env.working_path = env.blogdir = blogdir;
Desi.init(desi, env).then(function () { Desi.init(desi, env).then(function () {
// TODO move this 'create new post' logic to desirae proper // TODO move this 'create new post' logic to desirae proper
var collectionname = Object.keys(desi.config.collections)[0] var collectionname = Object.keys(desi.config.collections)[0],
, collection = desi.config.collections[collectionname] collection = desi.config.collections[collectionname],
, entity = {} entity = {};
; /*
/*
Desi.init(desi, env).then(function () { Desi.init(desi, env).then(function () {
env.url = desi.site.base_url + desi.site.base_path.replace(/^\/$/, ''); env.url = desi.site.base_url + desi.site.base_path.replace(/^\/$/, '');
env.base_url = desi.site.base_url; env.base_url = desi.site.base_url;
@ -201,75 +226,92 @@ function createPost(originalDir, blogdir, title, extra) {
// TODO use site.permalink or collection.permalink or something like that // TODO use site.permalink or collection.permalink or something like that
slug = Desi.slugify(post.title); slug = Desi.slugify(post.title);
// TODO as per config // TODO as per config
post.uuid = UUID.v4(); post.uuid = UUID.v4();
// TODO as per config for default collection and default format (jade, md, etc) // TODO as per config for default collection and default format (jade, md, etc)
filepath = path.join(blogdir, collectionname, slug + '.md'); filepath = path.join(blogdir, collectionname, slug + ".md");
displaypath = path.join(originalDir, 'posts', slug + '.md').replace(/^\/(Users|home)\/[^\/]+\//, '~/').replace(/ /g, '\\ '); displaypath = path
.join(originalDir, "posts", slug + ".md")
.replace(/^\/(Users|home)\/[^\/]+\//, "~/")
.replace(/ /g, "\\ ");
['updated', 'theme', 'layout', 'swatch'].forEach(function (key) { ["updated", "theme", "layout", "swatch"].forEach(function (key) {
if (!post[key]) { if (!post[key]) {
delete post[key]; delete post[key];
} }
}); });
Object.keys(post).forEach(function (key) { Object.keys(post).forEach(function (key) {
entity[key] = post[key]; entity[key] = post[key];
}); });
entity.slug = slug; entity.slug = slug;
post.permalink = Desi.permalinkify( post.permalink = Desi.permalinkify(
desi desi,
, collection.fallback_permalink || collection.permalink collection.fallback_permalink || collection.permalink,
, entity); entity
return Desi.fsapi.putFiles([{ );
path: filepath return Desi.fsapi
, contents: .putFiles(
'---\n' [
+ Desi.YAML.stringify(post).trim() {
+ '\n' path: filepath,
+ '---\n' contents:
+ '\n' "---\n" +
+ '\n' Desi.YAML.stringify(post).trim() +
}], { overwrite: false }).then(function (r) { "\n" +
var err "---\n" +
; "\n" +
"\n",
},
],
{ overwrite: false }
)
.then(function (r) {
var err;
if (r.error || r.errors.length) { if (r.error || r.errors.length) {
err = r.error || r.errors[0]; err = r.error || r.errors[0];
if (/exists/i.test(err.message)) { if (/exists/i.test(err.message)) {
console.error(''); console.error("");
console.error("Looks like that post already exists. Try a different name?"); console.error(
console.error(''); "Looks like that post already exists. Try a different name?"
console.error(''); );
} else { console.error("");
throw err; console.error("");
} else {
throw err;
}
} }
}
console.log(''); console.log("");
console.log(displaypath); console.log(displaypath);
console.log(''); console.log("");
console.log('Markdown: [' + post.title + '](' console.log(
+ desi.site.base_url "Markdown: [" +
+ path.join(desi.site.base_path, post.permalink) post.title +
+ ')' "](" +
); desi.site.base_url +
console.log('HTML: <a href="' path.join(desi.site.base_path, post.permalink) +
+ desi.site.base_url ")"
+ path.join(desi.site.base_path, post.permalink) );
+ '">' + post.title + '</a>' console.log(
); 'HTML: <a href="' +
console.log(''); desi.site.base_url +
console.log(''); path.join(desi.site.base_path, post.permalink) +
console.log('vim ' + displaypath); '">' +
console.log('(or emacs ' + displaypath + ', if you swing that way)'); post.title +
console.log(''); "</a>"
console.log(''); );
}); console.log("");
/* console.log("");
console.log("vim " + displaypath);
console.log("(or emacs " + displaypath + ", if you swing that way)");
console.log("");
console.log("");
});
/*
}); });
*/ */
}); });
@ -278,120 +320,132 @@ function createPost(originalDir, blogdir, title, extra) {
function initialize(displayPath, blogdir) { function initialize(displayPath, blogdir) {
console.info("\nCreating new blog", displayPath); console.info("\nCreating new blog", displayPath);
return fs.readdirAsync(blogdir).then(function (nodes) { return fs
// ignore dotfiles (.DS_Store, etc) .readdirAsync(blogdir)
nodes = nodes.filter(function (node) { .then(function (nodes) {
return !/^\./.test(node); // ignore dotfiles (.DS_Store, etc)
}); nodes = nodes.filter(function (node) {
return !/^\./.test(node);
});
if (nodes.length) { if (nodes.length) {
console.error("\n\tOops! It looks like that directory is already being used"); console.error(
console.error("\nIf you want you can DELETE it and start from scratch:"); "\n\tOops! It looks like that directory is already being used"
console.error("\n\trm -r '" + blogdir.replace("'", "'\"'\"'") + "'"); );
console.error("\nOr you can specify a different directory."); console.error(
console.error("\n"); "\nIf you want you can DELETE it and start from scratch:"
process.exit(1); );
} console.error("\n\trm -r '" + blogdir.replace("'", "'\"'\"'") + "'");
}).catch(function (/*err*/) { console.error("\nOr you can specify a different directory.");
// doesn't exist? No problamo (all the better, actually) console.error("\n");
return; process.exit(1);
}).then(function () {
return fsx.mkdirp(blogdir);
}).then(function () {
return new PromiseA(function (resolve, reject) {
var t = tar.Extract({ path: blogdir, strip: 1 })
, gunzip = zlib.createGunzip()
;
console.info("Downloading blog template...", displayPath);
request.get("https://github.com/DearDesi/desirae-blog-template/archive/v1.1.0.tar.gz")
.pipe(gunzip)
.pipe(t)
.on('end', resolve)
.on('error', reject)
;
});
}).then(function () {
var themes
;
themes = [
{ name: 'ruhoh-twitter'
, url: "https://github.com/DearDesi/ruhoh-twitter/archive/v1.0.0.tar.gz"
} }
, { name: 'ruhoh-bootstrap-2' })
, url: "https://github.com/DearDesi/ruhoh-bootstrap-2/archive/v1.0.1.tar.gz" .catch(function (/*err*/) {
} // doesn't exist? No problamo (all the better, actually)
]; return;
})
return forEachAsync(themes, function (theme) { .then(function () {
return fsx.mkdirp(blogdir);
})
.then(function () {
return new PromiseA(function (resolve, reject) { return new PromiseA(function (resolve, reject) {
var t = tar.Extract({ path: path.join(blogdir, 'themes', theme.name), strip: 1 }) var t = tar.Extract({ path: blogdir, strip: 1 }),
, gunzip = zlib.createGunzip() gunzip = zlib.createGunzip();
; console.info("Downloading blog template...", displayPath);
request
console.info("Downloading theme '" + theme.name + "'"); .get(
request.get(theme.url) "https://github.com/DearDesi/desirae-blog-template/archive/v1.1.0.tar.gz"
)
.pipe(gunzip) .pipe(gunzip)
.pipe(t) .pipe(t)
.on('end', resolve) .on("end", resolve)
.on('error', reject) .on("error", reject);
;
}); });
}); })
}).then(function () { .then(function () {
console.info("Done."); var themes;
console.info("\nTo start the web editor run this:");
console.info("\n\tdesi serve -d '" + blogdir.replace("'", "'\"'\"'") + "'");
})
;
}
themes = [
{
name: "ruhoh-twitter",
url:
"https://github.com/DearDesi/ruhoh-twitter/archive/v1.0.0.tar.gz",
},
{
name: "ruhoh-bootstrap-2",
url:
"https://github.com/DearDesi/ruhoh-bootstrap-2/archive/v1.0.1.tar.gz",
},
];
return forEachAsync(themes, function (theme) {
return new PromiseA(function (resolve, reject) {
var t = tar.Extract({
path: path.join(blogdir, "themes", theme.name),
strip: 1,
}),
gunzip = zlib.createGunzip();
console.info("Downloading theme '" + theme.name + "'");
request
.get(theme.url)
.pipe(gunzip)
.pipe(t)
.on("end", resolve)
.on("error", reject);
});
});
})
.then(function () {
console.info("Done.");
console.info("\nTo start the web editor run this:");
console.info(
"\n\tdesi serve -d '" + blogdir.replace("'", "'\"'\"'") + "'"
);
});
}
cli.main(function (args, options) { cli.main(function (args, options) {
init(); init();
var command = args[0] var command = args[0],
, blogdir = options.blogdir blogdir = options.blogdir,
, originalDir = blogdir originalDir = blogdir,
, displayPath displayPath;
;
if (!blogdir) { if (!blogdir) {
blogdir = path.resolve('./'); blogdir = path.resolve("./");
originalDir = './'; originalDir = "./";
} }
displayPath = path.resolve(originalDir) displayPath = path
.replace(/^\/(Users|home)\/[^\/]+\//, '~/') .resolve(originalDir)
.replace(/ /g, '\\ ') .replace(/^\/(Users|home)\/[^\/]+\//, "~/")
; .replace(/ /g, "\\ ");
if ('init' === command) { if ("init" === command) {
initialize(displayPath, blogdir); initialize(displayPath, blogdir);
return; return;
} }
if (!fs.existsSync(path.join(blogdir, 'site.yml'))) { if (!fs.existsSync(path.join(blogdir, "site.yml"))) {
console.error("Usage: desi [serve|init|post] -d ~/path/to/blog"); console.error("Usage: desi [serve|init|post] -d ~/path/to/blog");
console.error("(if ~/path/to/blog doesn't yet exist or doesn't have config.yml, site.yml, etc, " console.error(
+ "try `deardesi init -d ~/path/to/blog'"); "(if ~/path/to/blog doesn't yet exist or doesn't have config.yml, site.yml, etc, " +
"try `deardesi init -d ~/path/to/blog'"
);
process.exit(1); process.exit(1);
return; return;
} } else if ("build" === command) {
else if ('build' === command) {
build(blogdir); build(blogdir);
return; return;
} } else if ("post" === command) {
else if ('post' === command) {
createPost(originalDir, blogdir, args[1], args[2]); createPost(originalDir, blogdir, args[1], args[2]);
return; return;
} } else if ("serve" === command) {
else if ('serve' === command) {
serve(displayPath, blogdir); serve(displayPath, blogdir);
return; return;
} } else {
else {
console.error("Usage: desi [serve|init|post] -d ~/path/to/blog"); console.error("Usage: desi [serve|init|post] -d ~/path/to/blog");
return; return;
} }

View File

@ -1,15 +1,10 @@
{ {
"name": "deardesi", "name": "deardesi",
"version": "0.8.5", "version": "0.8.5",
"authors": [ "authors": ["AJ ONeal <awesome@coolaj86.com>"],
"AJ ONeal <awesome@coolaj86.com>"
],
"description": "A blogging platform in the browser. Wow!", "description": "A blogging platform in the browser. Wow!",
"main": "deardesi.js", "main": "deardesi.js",
"moduleType": [ "moduleType": ["globals", "node"],
"globals",
"node"
],
"keywords": [ "keywords": [
"dear", "dear",
"desi", "desi",
@ -21,13 +16,7 @@
], ],
"license": "Apache2", "license": "Apache2",
"homepage": "http://github.com/DearDesi/deardesi", "homepage": "http://github.com/DearDesi/deardesi",
"ignore": [ "ignore": ["**/.*", "node_modules", "bower_components", "test", "tests"],
"**/.*",
"node_modules",
"bower_components",
"test",
"tests"
],
"dependencies": { "dependencies": {
"escape-string-regexp": "~1.0.2", "escape-string-regexp": "~1.0.2",
"path": "~3.46.1", "path": "~3.46.1",

View File

@ -1,32 +1,27 @@
angular.module('myApp.services', []). angular.module("myApp.services", []).factory("Desirae", [
factory('Desirae', ['$q', '$http', function ($q, $http) { "$q",
var Desi = window.Desirae || require('./deardesi').Desirae "$http",
, desi = {/*TODO api_base: '/api'*/} function ($q, $http) {
; var Desi = window.Desirae || require("./deardesi").Desirae,
desi = {
/*TODO api_base: '/api'*/
};
// //
// 1. Transform (yml, slug, etc) // 1. Transform (yml, slug, etc)
// //
Desi.registerTransform( Desi.registerTransform("lint", window.DesiraeTransformCore.lint, {
'lint' collections: true,
, window.DesiraeTransformCore.lint });
, { collections: true } Desi.registerTransform("root", window.DesiraeTransformCore.root, {
); root: true,
Desi.registerTransform( });
'root' Desi.registerTransform("normalize", window.DesiraeTransformCore.normalize, {
, window.DesiraeTransformCore.root root: true,
, { root: true } collections: true,
); });
Desi.registerTransform( Desi.registerTransform("disqus", window.DesiraeTransformCore.disqus, {
'normalize' collections: true,
, window.DesiraeTransformCore.normalize });
, { root: true, collections: true }
);
Desi.registerTransform(
'disqus'
, window.DesiraeTransformCore.disqus
, { collections: true }
);
// //
// 2. Aggregate (rss, categories, tags, etc) // 2. Aggregate (rss, categories, tags, etc)
@ -36,60 +31,66 @@ angular.module('myApp.services', []).
// //
// 3. Datamap (ruhoh, desirae, jade, mustache, liquid) // 3. Datamap (ruhoh, desirae, jade, mustache, liquid)
// //
Desi.registerDataMapper('desirae', window.DesiraeDatamapCore); Desi.registerDataMapper("desirae", window.DesiraeDatamapCore);
Desi.registerDataMapper('desirae@1.0', window.DesiraeDatamapCore); Desi.registerDataMapper("desirae@1.0", window.DesiraeDatamapCore);
Desi.registerDataMapper('ruhoh', window.DesiraeDatamapRuhoh); Desi.registerDataMapper("ruhoh", window.DesiraeDatamapRuhoh);
Desi.registerDataMapper('ruhoh@1.0', window.DesiraeDatamapRuhoh); Desi.registerDataMapper("ruhoh@1.0", window.DesiraeDatamapRuhoh);
Desi.registerDataMapper('ruhoh@2.6', window.DesiraeDatamapRuhoh); Desi.registerDataMapper("ruhoh@2.6", window.DesiraeDatamapRuhoh);
// //
// 4. Render (md -> html, less -> css, etc) // 4. Render (md -> html, less -> css, etc)
// //
Desi.registerRenderer( Desi.registerRenderer("js", window.DesiraeRenderCss, {
'js' themes: true,
, window.DesiraeRenderCss assets: true,
, { themes: true, assets: true } });
); Desi.registerRenderer("css", window.DesiraeRenderCss, {
Desi.registerRenderer( themes: true,
'css' assets: true,
, window.DesiraeRenderCss
, { themes: true, assets: true }
);
['html', 'htm', 'xhtm', 'xhtml'].forEach(function (ext) {
Desi.registerRenderer(
ext
, window.DesiraeRenderHtml
, { root: true, collections: true, themes: true, assets: true }
);
}); });
['md', 'markdown', 'mdown', 'mkdn', 'mkd', 'mdwn', 'mdtxt', 'mdtext'].forEach(function (ext) { ["html", "htm", "xhtm", "xhtml"].forEach(function (ext) {
Desi.registerRenderer( Desi.registerRenderer(ext, window.DesiraeRenderHtml, {
ext root: true,
, window.DesiraeRenderMarkdown collections: true,
, { root: true, collections: true } themes: true,
); assets: true,
});
}); });
Desi.registerRenderer( [
'jade' "md",
, window.DesiraeRenderJade "markdown",
, { root: true, collections: true, themes: true } "mdown",
); "mkdn",
"mkd",
"mdwn",
"mdtxt",
"mdtext",
].forEach(function (ext) {
Desi.registerRenderer(ext, window.DesiraeRenderMarkdown, {
root: true,
collections: true,
});
});
Desi.registerRenderer("jade", window.DesiraeRenderJade, {
root: true,
collections: true,
themes: true,
});
function gdrive2host(str) { function gdrive2host(str) {
// https://drive.google.com/folderview?id=0ByLnfhJOd1-baUh1Wms0US16QkE&usp=sharing // https://drive.google.com/folderview?id=0ByLnfhJOd1-baUh1Wms0US16QkE&usp=sharing
// https://googledrive.com/host/0ByLnfhJOd1-baUh1Wms0US16QkE // https://googledrive.com/host/0ByLnfhJOd1-baUh1Wms0US16QkE
var m var m;
;
str = str || ''; str = str || "";
m = str.match(/(?=drive.*google|google.*drive).*folderview.*id=([^&]+)/i); m = str.match(/(?=drive.*google|google.*drive).*folderview.*id=([^&]+)/i);
console.log(m); console.log(m);
if (m && m[1]) { if (m && m[1]) {
return 'https://googledrive.com/host/' + m[1]; return "https://googledrive.com/host/" + m[1];
} }
} }
@ -103,42 +104,42 @@ angular.module('myApp.services', []).
// https://www.dropbox.com/s/3n20djtrs2p0j9k/index.html?dl=0 // https://www.dropbox.com/s/3n20djtrs2p0j9k/index.html?dl=0
// https://dl.dropboxusercontent.com/s/3n20djtrs2p0j9k/index.html // https://dl.dropboxusercontent.com/s/3n20djtrs2p0j9k/index.html
str = str || ''; str = str || "";
if (!str.match(/dropboxusercontent\.com\/u\/([^\/]+)\/index.html/)) { if (!str.match(/dropboxusercontent\.com\/u\/([^\/]+)\/index.html/)) {
window.alert("Sorry, Desi can't use that type of dropbox link." window.alert(
+ "\n\n1. Open the Dropbox folder on your computer" "Sorry, Desi can't use that type of dropbox link." +
+ "\n (The DropBox app must be installed)" "\n\n1. Open the Dropbox folder on your computer" +
+ "\n\n2. Open the Public folder" "\n (The DropBox app must be installed)" +
+ "\n (if you don't have a Public folder, your account doesn't support hosting websites and you're simply out of luck)" "\n\n2. Open the Public folder" +
+ "\n\n2. Create a new file called index.html" "\n (if you don't have a Public folder, your account doesn't support hosting websites and you're simply out of luck)" +
+ "\n\n3. Right-click on index.html" "\n\n2. Create a new file called index.html" +
+ "\n\n4. Select 'Copy Public Link'" "\n\n3. Right-click on index.html" +
+ "\n\n5. Paste that link as the URL for Desi" "\n\n4. Select 'Copy Public Link'" +
); "\n\n5. Paste that link as the URL for Desi"
);
return; return;
} }
return str.replace(/\/index\.html$/, ''); return str.replace(/\/index\.html$/, "");
} }
function splitUrl(str) { function splitUrl(str) {
var m var m;
;
str = str || ''; str = str || "";
m = str.match(/(https?:\/\/)?([^\.\/?#]+\.[^\/?#]+)(\/[^#?]+)?/i); m = str.match(/(https?:\/\/)?([^\.\/?#]+\.[^\/?#]+)(\/[^#?]+)?/i);
console.log(m); console.log(m);
if (!m || !m[2]) { if (!m || !m[2]) {
return; return;
} }
return { return {
baseUrl: (m[1] || 'http://') + m[2] baseUrl: (m[1] || "http://") + m[2],
, basePath: (m[3] && m[3].replace(/\/$/, '')) || '/' basePath: (m[3] && m[3].replace(/\/$/, "")) || "/",
}; };
} }
function getBlogdir () { function getBlogdir() {
return $http.get('/api/fs/rootdir').then(function (resp) { return $http.get("/api/fs/rootdir").then(function (resp) {
desi.blogdir = resp.data; desi.blogdir = resp.data;
return resp.data; return resp.data;
}); });
@ -146,18 +147,16 @@ angular.module('myApp.services', []).
getBlogdir(); getBlogdir();
return { return {
splitUrl: splitUrl splitUrl: splitUrl,
, gdrive2host: gdrive2host gdrive2host: gdrive2host,
, dropbox2host: dropbox2host dropbox2host: dropbox2host,
, reset: function () { reset: function () {
desi = {}; desi = {};
return getBlogdir(); return getBlogdir();
} },
, toDesiDate: Desi.toLocaleDate toDesiDate: Desi.toLocaleDate,
, meta: function () { meta: function () {
var d = $q.defer() var d = $q.defer();
;
if (desi.meta) { if (desi.meta) {
d.resolve(desi); d.resolve(desi);
return d.promise; return d.promise;
@ -168,11 +167,9 @@ angular.module('myApp.services', []).
}); });
return d.promise; return d.promise;
} },
, build: function (env) { build: function (env) {
var d = $q.defer() var d = $q.defer();
;
if (desi.built) { if (desi.built) {
d.resolve(desi); d.resolve(desi);
return d.promise; return d.promise;
@ -183,11 +180,9 @@ angular.module('myApp.services', []).
}); });
return d.promise; return d.promise;
} },
, write: function (env) { write: function (env) {
var d = $q.defer() var d = $q.defer();
;
if (desi.written) { if (desi.written) {
d.resolve(desi); d.resolve(desi);
return d.promise; return d.promise;
@ -198,10 +193,10 @@ angular.module('myApp.services', []).
}); });
return d.promise; return d.promise;
} },
, putFiles: function (files) { putFiles: function (files) {
return $q.when(Desi.fsapi.putFiles(files)); return $q.when(Desi.fsapi.putFiles(files));
} },
}; };
}] },
); ]);

View File

@ -1,9 +1,13 @@
'use strict'; "use strict";
angular.module('myApp.version.interpolate-filter', []) angular
.module("myApp.version.interpolate-filter", [])
.filter('interpolate', ['version', function(version) { .filter("interpolate", [
return function(text) { "version",
return String(text).replace(/\%VERSION\%/mg, version); function (version) {
}; return function (text) {
}]); return String(text).replace(/\%VERSION\%/gm, version);
};
},
]);

View File

@ -1,15 +1,19 @@
'use strict'; "use strict";
describe('myApp.version module', function() { describe("myApp.version module", function () {
beforeEach(module('myApp.version')); beforeEach(module("myApp.version"));
describe('interpolate filter', function() { describe("interpolate filter", function () {
beforeEach(module(function($provide) { beforeEach(
$provide.value('version', 'TEST_VER'); module(function ($provide) {
})); $provide.value("version", "TEST_VER");
})
);
it('should replace VERSION', inject(function(interpolateFilter) { it("should replace VERSION", inject(function (interpolateFilter) {
expect(interpolateFilter('before %VERSION% after')).toEqual('before TEST_VER after'); expect(interpolateFilter("before %VERSION% after")).toEqual(
"before TEST_VER after"
);
})); }));
}); });
}); });

View File

@ -1,9 +1,13 @@
'use strict'; "use strict";
angular.module('myApp.version.version-directive', []) angular
.module("myApp.version.version-directive", [])
.directive('appVersion', ['version', function(version) { .directive("appVersion", [
return function(scope, elm, attrs) { "version",
elm.text(version); function (version) {
}; return function (scope, elm, attrs) {
}]); elm.text(version);
};
},
]);

View File

@ -1,16 +1,16 @@
'use strict'; "use strict";
describe('myApp.version module', function() { describe("myApp.version module", function () {
beforeEach(module('myApp.version')); beforeEach(module("myApp.version"));
describe('app-version directive', function() { describe("app-version directive", function () {
it('should print current version', function() { it("should print current version", function () {
module(function($provide) { module(function ($provide) {
$provide.value('version', 'TEST_VER'); $provide.value("version", "TEST_VER");
}); });
inject(function($compile, $rootScope) { inject(function ($compile, $rootScope) {
var element = $compile('<span app-version></span>')($rootScope); var element = $compile("<span app-version></span>")($rootScope);
expect(element.text()).toEqual('TEST_VER'); expect(element.text()).toEqual("TEST_VER");
}); });
}); });
}); });

View File

@ -1,8 +1,9 @@
'use strict'; "use strict";
angular.module('myApp.version', [ angular
'myApp.version.interpolate-filter', .module("myApp.version", [
'myApp.version.version-directive' "myApp.version.interpolate-filter",
]) "myApp.version.version-directive",
])
.value('version', '0.8.0'); .value("version", "0.8.0");

View File

@ -1,11 +1,11 @@
'use strict'; "use strict";
describe('myApp.version module', function() { describe("myApp.version module", function () {
beforeEach(module('myApp.version')); beforeEach(module("myApp.version"));
describe('version service', function() { describe("version service", function () {
it('should return current version', inject(function(version) { it("should return current version", inject(function (version) {
expect(version).toEqual('0.1'); expect(version).toEqual("0.1");
})); }));
}); });
}); });

View File

@ -1,12 +1,8 @@
'use strict'; "use strict";
var fsapi = require('desirae/lib/node-adapters').fsapi
;
var fsapi = require("desirae/lib/node-adapters").fsapi;
module.exports.create = function (options) { module.exports.create = function (options) {
var restful = {} var restful = {};
;
// //
// Required for desirae // Required for desirae
// //
@ -16,18 +12,24 @@ module.exports.create = function (options) {
return; return;
} }
var opts = {} var opts = {},
, dirnames = req.query.dir && [req.query.dir] || (req.query.dirs && req.query.dirs.split(/,/g)) || req.body.dirs dirnames =
; (req.query.dir && [req.query.dir]) ||
(req.query.dirs && req.query.dirs.split(/,/g)) ||
req.body.dirs;
if (!dirnames || !dirnames.length) { if (!dirnames || !dirnames.length) {
res.send({ error: "please specify GET w/ req.query.dir or POST w/ _method=GET&dirs=path/to/thing,..." }); res.send({
error:
"please specify GET w/ req.query.dir or POST w/ _method=GET&dirs=path/to/thing,...",
});
return; return;
} }
if (!dirnames.every(function (dirname) { if (
return 'string' === typeof dirname; !dirnames.every(function (dirname) {
})) { return "string" === typeof dirname;
})
) {
res.send({ error: "malformed request: " + JSON.stringify(dirnames) }); res.send({ error: "malformed request: " + JSON.stringify(dirnames) });
return; return;
} }
@ -42,13 +44,13 @@ module.exports.create = function (options) {
opts.extensions = req.query.extensions.split(/,/g); opts.extensions = req.query.extensions.split(/,/g);
} }
if ('true' === req.query.dotfiles) { if ("true" === req.query.dotfiles) {
opts.dotfiles = true; opts.dotfiles = true;
} }
if ('false' === req.query.sha1sum) { if ("false" === req.query.sha1sum) {
opts.sha1sum = false; opts.sha1sum = false;
} }
if ('true' === req.query.contents) { if ("true" === req.query.contents) {
opts.contents = true; opts.contents = true;
} }
@ -68,11 +70,15 @@ module.exports.create = function (options) {
return; return;
} }
var filepaths = req.query.path && [req.query.path] || (req.query.paths && req.query.paths.split(/,/g)) || req.body.paths var filepaths =
; (req.query.path && [req.query.path]) ||
(req.query.paths && req.query.paths.split(/,/g)) ||
req.body.paths;
if (!filepaths || !filepaths.length) { if (!filepaths || !filepaths.length) {
res.send({ error: "please specify GET w/ req.query.path or POST _method=GET&paths=path/to/thing,..." }); res.send({
error:
"please specify GET w/ req.query.path or POST _method=GET&paths=path/to/thing,...",
});
return; return;
} }
@ -86,15 +92,15 @@ module.exports.create = function (options) {
}; };
restful.putFiles = function (req, res, next) { restful.putFiles = function (req, res, next) {
if (!(/^POST|PUT$/i.test(req.method) || /^POST|PUT$/i.test(req.query._method))) { if (
!(/^POST|PUT$/i.test(req.method) || /^POST|PUT$/i.test(req.query._method))
) {
next(); next();
return; return;
} }
var opts = {} var opts = {},
, files = req.body.files files = req.body.files;
;
if (!files || !files.length) { if (!files || !files.length) {
res.send({ error: "please specify POST w/ req.body.files" }); res.send({ error: "please specify POST w/ req.body.files" });
return; return;
@ -107,16 +113,16 @@ module.exports.create = function (options) {
}; };
restful.copy = function (req, res, next) { restful.copy = function (req, res, next) {
if (!(/^POST|PUT$/i.test(req.method) || /^POST|PUT$/i.test(req.query._method))) { if (
!(/^POST|PUT$/i.test(req.method) || /^POST|PUT$/i.test(req.query._method))
) {
next(); next();
return; return;
} }
var opts = {} var opts = {},
, files = req.body.files files = req.body.files;
; if ("object" !== typeof files || !Object.keys(files).length) {
if ('object' !== typeof files || !Object.keys(files).length) {
res.send({ error: "please specify POST w/ req.body.files" }); res.send({ error: "please specify POST w/ req.body.files" });
return; return;
} }

View File

@ -2,129 +2,191 @@
<!--[if lt IE 7]> <html lang="en" ng-app="myApp" class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]--> <!--[if lt IE 7]> <html lang="en" ng-app="myApp" class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
<!--[if IE 7]> <html lang="en" ng-app="myApp" class="no-js lt-ie9 lt-ie8"> <![endif]--> <!--[if IE 7]> <html lang="en" ng-app="myApp" class="no-js lt-ie9 lt-ie8"> <![endif]-->
<!--[if IE 8]> <html lang="en" ng-app="myApp" class="no-js lt-ie9"> <![endif]--> <!--[if IE 8]> <html lang="en" ng-app="myApp" class="no-js lt-ie9"> <![endif]-->
<!--[if gt IE 8]><!--> <html lang="en" ng-app="myApp" class="no-js"> <!--<![endif]--> <!--[if gt IE 8]><!-->
<head> <html lang="en" ng-app="myApp" class="no-js">
<meta charset="utf-8"> <!--<![endif]-->
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<title>Desi, the DIY Blog Platform</title> <title>Desi, the DIY Blog Platform</title>
<meta name="description" content="Desi is the DIY blog platform for normal people. You can build your blog with Desi in your browser and then host it on Google Drive, DropBox, Github, or a good ol' fashion web host via ftp."> <meta
name="description"
content="Desi is the DIY blog platform for normal people. You can build your blog with Desi in your browser and then host it on Google Drive, DropBox, Github, or a good ol' fashion web host via ftp."
/>
<!-- Style --> <!-- Style -->
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="bower_components/html5-boilerplate/css/normalize.css"> <link
<link rel="stylesheet" href="bower_components/html5-boilerplate/css/main.css"> rel="stylesheet"
<link rel="stylesheet" href="bower_components/bootstrap/dist/css/bootstrap.min.css"><!-- just as a fallback --> href="bower_components/html5-boilerplate/css/normalize.css"
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootswatch/3.3.1/spacelab/bootstrap.min.css"> />
<link
rel="stylesheet"
href="bower_components/html5-boilerplate/css/main.css"
/>
<link
rel="stylesheet"
href="bower_components/bootstrap/dist/css/bootstrap.min.css"
/>
<!-- just as a fallback -->
<link
rel="stylesheet"
href="//maxcdn.bootstrapcdn.com/bootswatch/3.3.1/spacelab/bootstrap.min.css"
/>
<script src="bower_components/html5-boilerplate/js/vendor/modernizr-2.6.2.min.js"></script> <script src="bower_components/html5-boilerplate/js/vendor/modernizr-2.6.2.min.js"></script>
</head> </head>
<body> <body>
<!--[if lt IE 7]>
<p class="browsehappy">
You are using an <strong>outdated</strong> browser. Please
<a href="http://browsehappy.com/">upgrade your browser</a> to improve
your experience.
</p>
<![endif]-->
<!--[if lt IE 7]> <!--.navbar.navbar-default.navbar-fixed-top-->
<p class="browsehappy">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.</p> <div
<![endif]--> style="margin-bottom: 0; border-top-width: 0"
class="navbar navbar-default"
>
<div class="container">
<div class="navbar-header">
<div
style="padding-top: 9px; padding-left: 9px; padding-bottom: 9px"
class="pull-left"
>
<img
ng-src="http://dropsha.re/files/VY15+v8/desirae-parker-crop.jpg"
style="border: 1px solid grey; height: 54px; width: 54px"
class="navbar-logo"
/>
</div>
<a
href="#/"
style="padding-top: 23px; padding-left: 25px"
class="navbar-brand"
>Desi</a
>
<div style="padding-top: 9px">
<button
type="button"
ng-init="navCollapsed = true"
ng-click="navCollapsed = !navCollapsed"
class="navbar-toggle"
>
<span class="icon-bar"></span><span class="icon-bar"></span
><span class="icon-bar"></span>
</button>
</div>
</div>
<!--.navbar.navbar-default.navbar-fixed-top-->
<div style="margin-bottom: 0; border-top-width: 0;" class="navbar navbar-default">
<div class="container">
<div class="navbar-header">
<div <div
style="padding-top: 9px; padding-left: 9px; padding-bottom: 9px;" id="navbar-main"
class="pull-left"><img ng-class="!navCollapsed &amp;&amp; 'in'"
ng-src="http://dropsha.re/files/VY15+v8/desirae-parker-crop.jpg" class="navbar-collapse collapse"
style="border: 1px solid grey; height: 54px; width: 54px;" >
class="navbar-logo"/></div> <ul style="padding-top: 9px" class="nav navbar-nav">
<a href="#/" <li><a href="#/authors">Authors</a></li>
style="padding-top: 23px; padding-left: 25px;" <li><a href="#/site">Site</a></li>
class="navbar-brand">Desi</a> <li><a href="#/post">Post</a></li>
<li><a href="#/build">Build</a></li>
<div style="padding-top: 9px;"> </ul>
<button type="button" ng-init="navCollapsed = true" ng-click="navCollapsed = !navCollapsed" class="navbar-toggle"><span class="icon-bar"></span><span class="icon-bar"></span><span class="icon-bar"></span></button>
</div> </div>
</div> </div>
<div id="navbar-main" ng-class="!navCollapsed &amp;&amp; 'in'" class="navbar-collapse collapse">
<ul style="padding-top: 9px;" class="nav navbar-nav">
<li><a href="#/authors">Authors</a></li>
<li><a href="#/site">Site</a></li>
<li><a href="#/post">Post</a></li>
<li><a href="#/build">Build</a></li>
</ul>
</div>
</div> </div>
</div>
<div ng-view></div> <div ng-view></div>
<footer> <footer>
<center> <center>
<p> <p>
<!-- http://googlewebmastercentral.blogspot.com/2009/02/specify-your-canonical.html --> <!-- http://googlewebmastercentral.blogspot.com/2009/02/specify-your-canonical.html -->
<!-- also needs updating at http://plus.google.com/me/about/edit/co --> <!-- also needs updating at http://plus.google.com/me/about/edit/co -->
<a href="mailto:develop@dear.desi" rel="me">develop@dear.desi</a> <a href="mailto:develop@dear.desi" rel="me">develop@dear.desi</a>
| |
<a href="https://twitter.com/dearbesiblog?rel=author" rel="me">Twitter</a> <a href="https://twitter.com/dearbesiblog?rel=author" rel="me"
<!--a href="https://www.facebook.com/coolaj86?rel=author" rel="me">Facebook</a--> >Twitter</a
| >
<a href="https://github.com/DearDesi/desirae?rel=author" rel="me">Github</a> (v<span app-version></span>) <!--a href="https://www.facebook.com/coolaj86?rel=author" rel="me">Facebook</a-->
<!--a href="https://plus.google.com/111222501744950155474?rel=author" data-user="AJ ONeal" rel="me">Google+</a --> |
| <a href="https://github.com/DearDesi/desirae?rel=author" rel="me"
<a href="https://www.youtube.com/watch?v=pFAKAWP_sec" rel="me">YouTube</a> >Github</a
| >
<a href="http://www.apache.org/licenses/LICENSE-2.0">Apache 2 License</a> (v<span app-version></span>)
| <!--a href="https://plus.google.com/111222501744950155474?rel=author" data-user="AJ ONeal" rel="me">Google+</a -->
<a href="http://opensource.org/licenses/MIT">MIT License</a> |
</p> <a href="https://www.youtube.com/watch?v=pFAKAWP_sec" rel="me"
<p>© AJ ONeal Tech LLC 2015 >YouTube</a
with help from >
<a href="http://angularjs.org" target="_blank" title="Superheroic JavaScript MVW Framework">AngularJS</a>, |
<a href="http://iojs.org" target="_blank" <a href="http://www.apache.org/licenses/LICENSE-2.0"
title="Open source, cross-platform server-side JavaScript runtime environment">io.js</a>, >Apache 2 License</a
and <a href="http://twitter.github.com/bootstrap/" target="_blank">Twitter Bootstrap</a> >
</p> |
</center> <a href="http://opensource.org/licenses/MIT">MIT License</a>
</footer> </p>
<p>
© AJ ONeal Tech LLC 2015 with help from
<a
href="http://angularjs.org"
target="_blank"
title="Superheroic JavaScript MVW Framework"
>AngularJS</a
>,
<a
href="http://iojs.org"
target="_blank"
title="Open source, cross-platform server-side JavaScript runtime environment"
>io.js</a
>, and
<a href="http://twitter.github.com/bootstrap/" target="_blank"
>Twitter Bootstrap</a
>
</p>
</center>
</footer>
<!-- Deps --> <!-- Deps -->
<script src="./bower_components/bluebird/js/browser/bluebird.js"></script> <script src="./bower_components/bluebird/js/browser/bluebird.js"></script>
<script src="./bower_components/mustache/mustache.js"></script> <script src="./bower_components/mustache/mustache.js"></script>
<script src="./bower_components/markdown-it/dist/markdown-it.js"></script> <script src="./bower_components/markdown-it/dist/markdown-it.js"></script>
<script src="./bower_components/jade/jade.js"></script> <script src="./bower_components/jade/jade.js"></script>
<script src="./bower_components/js-yaml/dist/js-yaml.js"></script> <script src="./bower_components/js-yaml/dist/js-yaml.js"></script>
<script src="./bower_components/path/path.js"></script> <script src="./bower_components/path/path.js"></script>
<script src="./bower_components/node-uuid/uuid.js"></script> <script src="./bower_components/node-uuid/uuid.js"></script>
<script src="./bower_components/forEachAsync/forEachAsync.js"></script> <script src="./bower_components/forEachAsync/forEachAsync.js"></script>
<!-- Libs --> <!-- Libs -->
<script src="./bower_components/desirae/lib/verify-config.js"></script> <script src="./bower_components/desirae/lib/verify-config.js"></script>
<!-- Desi --> <!-- Desi -->
<script src="./bower_components/desirae/desirae.js"></script> <script src="./bower_components/desirae/desirae.js"></script>
<script src="./bower_components/desirae/lib/frontmatter.js"></script> <script src="./bower_components/desirae/lib/frontmatter.js"></script>
<script src="./bower_components/desirae/lib/browser-adapters.js"></script> <script src="./bower_components/desirae/lib/browser-adapters.js"></script>
<script src="./bower_components/desirae/lib/utils.js"></script> <script src="./bower_components/desirae/lib/utils.js"></script>
<script src="./bower_components/desirae/lib/transform-core.js"></script> <script src="./bower_components/desirae/lib/transform-core.js"></script>
<script src="./bower_components/desirae/lib/aggregate-core.js"></script> <script src="./bower_components/desirae/lib/aggregate-core.js"></script>
<script src="./bower_components/desirae/lib/datamap-core.js"></script> <script src="./bower_components/desirae/lib/datamap-core.js"></script>
<script src="./bower_components/desirae/lib/render-core.js"></script> <script src="./bower_components/desirae/lib/render-core.js"></script>
<script src="./bower_components/desirae-datamap-ruhoh/datamapper-ruhoh.js"></script> <script src="./bower_components/desirae-datamap-ruhoh/datamapper-ruhoh.js"></script>
<!-- UX Using Angular, but not getting fancy --> <!-- UX Using Angular, but not getting fancy -->
<script src="./bower_components/angular/angular.js"></script> <script src="./bower_components/angular/angular.js"></script>
<script src="./bower_components/angular-route/angular-route.js"></script> <script src="./bower_components/angular-route/angular-route.js"></script>
<script src="./bower_components/md5/build/md5.min.js"></script> <script src="./bower_components/md5/build/md5.min.js"></script>
<script src="./app.js"></script> <script src="./app.js"></script>
<script src="./views/about/about.js"></script> <script src="./views/about/about.js"></script>
<script src="./views/authors/authors.js"></script> <script src="./views/authors/authors.js"></script>
<script src="./views/site/site.js"></script> <script src="./views/site/site.js"></script>
<script src="./views/configure/configure.js"></script> <script src="./views/configure/configure.js"></script>
<script src="./views/build/build.js"></script> <script src="./views/build/build.js"></script>
<script src="./views/post/post.js"></script> <script src="./views/post/post.js"></script>
<script src="components/desirae/desirae.js"></script> <script src="components/desirae/desirae.js"></script>
<script src="components/version/version.js"></script> <script src="components/version/version.js"></script>
<script src="components/version/version-directive.js"></script> <script src="components/version/version-directive.js"></script>
<script src="components/version/interpolate-filter.js"></script> <script src="components/version/interpolate-filter.js"></script>
</body>
</body>
</html> </html>

View File

@ -4,6 +4,7 @@
"description": "A nice, friendly tool to help you get set up and start blogging, built on the Desirae blogging platform", "description": "A nice, friendly tool to help you get set up and start blogging, built on the Desirae blogging platform",
"main": "server.js", "main": "server.js",
"scripts": { "scripts": {
"prettier": "prettier --write './**/*.{js,css,json,md,html}'",
"test": "echo \"Error: no test specified\" && exit 1" "test": "echo \"Error: no test specified\" && exit 1"
}, },
"bin": { "bin": {

View File

@ -1,36 +1,31 @@
'use strict'; "use strict";
var path = require('path'); var path = require("path");
function create(options) { function create(options) {
var connect = require('connect') var connect = require("connect"),
, query = require('connect-query') query = require("connect-query"),
, bodyParser = require('body-parser') bodyParser = require("body-parser"),
, serveStatic = require('serve-static') serveStatic = require("serve-static"),
, send = require('connect-send-json') send = require("connect-send-json"),
app = connect(),
, app = connect() restful = require("./desirae-http-api").create(options);
, restful = require('./desirae-http-api').create(options)
;
app app
.use(send.json()) .use(send.json())
.use(query()) .use(query())
.use(bodyParser.json({ limit: 10 * 1024 * 1024 })) // 10mb .use(bodyParser.json({ limit: 10 * 1024 * 1024 })) // 10mb
.use(require('compression')()) .use(require("compression")());
;
// //
// Keeping the API *required* by desirae super minimal // Keeping the API *required* by desirae super minimal
// so that it can be implemented easily in any language // so that it can be implemented easily in any language
// //
app app
.use('/api/fs/static', serveStatic(options.blogdir)) .use("/api/fs/static", serveStatic(options.blogdir))
.use('/api/fs/walk', restful.walk) .use("/api/fs/walk", restful.walk)
.use('/api/fs/files', restful.getFiles) .use("/api/fs/files", restful.getFiles)
.use('/api/fs/files', restful.putFiles) .use("/api/fs/files", restful.putFiles)
.use('/api/fs/copy', restful.copy) .use("/api/fs/copy", restful.copy);
;
// end Desirae API // end Desirae API
if (options.tmpdir) { if (options.tmpdir) {
@ -38,32 +33,30 @@ function create(options) {
} }
// this is used by DearDesi, but not required for desirae // this is used by DearDesi, but not required for desirae
app app.use("/api/fs/rootdir", function (req, res) {
.use('/api/fs/rootdir', function (req, res) { var pathname = path.resolve(options.blogdir);
var pathname = path.resolve(options.blogdir) res.send({
; path: pathname,
name: path.basename(pathname),
res.send({ relativePath: path.dirname(pathname),
path: pathname });
, name: path.basename(pathname) return;
, relativePath: path.dirname(pathname) });
});
return;
})
;
app app
// the AngularJS App // the AngularJS App
.use(serveStatic(__dirname)) .use(serveStatic(__dirname))
// TODO change file requests to '/blog' // TODO change file requests to '/blog'
//.use(serveStatic(options.blogdir)) //.use(serveStatic(options.blogdir))
.use('/blog', serveStatic(options.blogdir)) .use("/blog", serveStatic(options.blogdir))
.use('/compiled_dev', serveStatic(path.join(options.blogdir, '/compiled_dev'))) .use(
.use('/compiled', serveStatic(path.join(options.blogdir, '/compiled'))) "/compiled_dev",
; serveStatic(path.join(options.blogdir, "/compiled_dev"))
)
.use("/compiled", serveStatic(path.join(options.blogdir, "/compiled")));
return app; return app;
} }
module.exports = create({ blogdir: path.join(__dirname, 'blog') }); module.exports = create({ blogdir: path.join(__dirname, "blog") });
module.exports.create = create; module.exports.create = create;

View File

@ -1,9 +1,11 @@
<div class="container"> <div class="container">
<div class="row"> <div class="row">
<div class="col-xs-12"> <div class="col-xs-12">
<div class="page-header"> <div class="page-header">
<h1>Welcome to Desi! <small ng-bind="'(v%VERSION%)' | interpolate"></small></h1> <h1>
Welcome to Desi!
<small ng-bind="'(v%VERSION%)' | interpolate"></small>
</h1>
</div> </div>
<div class="jumbotron"> <div class="jumbotron">
@ -11,13 +13,12 @@
<div class="col-lg-7"> <div class="col-lg-7">
<p>Setup your new blog in just 5 minutes.</p> <p>Setup your new blog in just 5 minutes.</p>
</div> </div>
<div class="col-lg-5"> <div class="col-lg-5"></div>
</div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-lg-7"> <div class="col-lg-7">
<!-- iframe width="560" height="315" src="//www.youtube.com/embed/pFAKAWP_sec" frameborder="0" allowfullscreen></iframe --> <!-- iframe width="560" height="315" src="//www.youtube.com/embed/pFAKAWP_sec" frameborder="0" allowfullscreen></iframe -->
<br/> <br />
<p>Run these commands in Terminal:</p> <p>Run these commands in Terminal:</p>
<pre> <pre>
<code>curl -fsSL bit.ly/install-deardesi | bash <code>curl -fsSL bit.ly/install-deardesi | bash
@ -28,18 +29,28 @@ open ~/Desktop/my-blog
desi serve -d ~/Desktop/my-blog</code> desi serve -d ~/Desktop/my-blog</code>
</pre> </pre>
<br/> <br />
<p>Then open <a href="http://local.dear.desi:65080">http://local.dear.desi:65080</a> in your browser.</p> <p>
Then open
<a href="http://local.dear.desi:65080"
>http://local.dear.desi:65080</a
>
in your browser.
</p>
</div> </div>
<div class="col-lg-5"> <div class="col-lg-5">
<h2>Why Desi?</h2> <h2>Why Desi?</h2>
<br/> <br />
<ul> <ul>
<li>Built in JavaScript <li>
Built in JavaScript
<ul> <ul>
<li>Write content in Markdown, Jade, or HTML</li> <li>Write content in Markdown, Jade, or HTML</li>
<li>Mustache Templates</li> <li>Mustache Templates</li>
<li>Use <a href="http://ruhoh.com">ruhoh</a> themes (or roll your own)</li> <li>
Use <a href="http://ruhoh.com">ruhoh</a> themes (or roll
your own)
</li>
</ul> </ul>
</li> </li>
<li>Build your blog right in your browser</li> <li>Build your blog right in your browser</li>
@ -49,8 +60,10 @@ desi serve -d ~/Desktop/my-blog</code>
<li>No Ruby version Hell - it'll still work in 6 months! :-D</li> <li>No Ruby version Hell - it'll still work in 6 months! :-D</li>
</ul> </ul>
<h3>What are you waiting for?</h3> <h3>What are you waiting for?</h3>
<br/> <br />
<a class="btn btn-primary btn-lg pull-right" href="/#authors">Get Started!</a> <a class="btn btn-primary btn-lg pull-right" href="/#authors"
>Get Started!</a
>
</div> </div>
</div> </div>
</div> </div>

View File

@ -1,14 +1,16 @@
'use strict'; "use strict";
angular.module('myApp.about', ['ngRoute']) angular
.module("myApp.about", ["ngRoute"])
.config(['$routeProvider', function($routeProvider) { .config([
$routeProvider.when('/about', { "$routeProvider",
templateUrl: 'views/about/about.html', function ($routeProvider) {
controller: 'AboutCtrl' $routeProvider.when("/about", {
}); templateUrl: "views/about/about.html",
}]) controller: "AboutCtrl",
});
},
])
.controller('AboutCtrl', [function() { .controller("AboutCtrl", [function () {}]);
}]);

View File

@ -1,16 +1,13 @@
'use strict'; "use strict";
describe('myApp.view2 module', function() { describe("myApp.view2 module", function () {
beforeEach(module("myApp.view2"));
beforeEach(module('myApp.view2')); describe("view2 controller", function () {
it("should ....", inject(function ($controller) {
describe('view2 controller', function(){
it('should ....', inject(function($controller) {
//spec body //spec body
var view2Ctrl = $controller('View2Ctrl'); var view2Ctrl = $controller("View2Ctrl");
expect(view2Ctrl).toBeDefined(); expect(view2Ctrl).toBeDefined();
})); }));
}); });
}); });

View File

@ -7,39 +7,50 @@
<div class="row" ng-if="Authors.authors"> <div class="row" ng-if="Authors.authors">
<div class="col-md-offset-1 col-md-8"> <div class="col-md-offset-1 col-md-8">
<div class="form-group"> <div class="form-group">
<select <select
ng-options="author as author.filename for (handle, author) in Authors.authors" ng-options="author as author.filename for (handle, author) in Authors.authors"
class="form-control" class="form-control"
ng-model="Authors.selectedAuthor" ng-model="Authors.selectedAuthor"
ng-change="Authors.selectAuthor()" ng-change="Authors.selectAuthor()"
></select> ></select>
</div> </div>
</div> </div>
<br/> <br />
</div> </div>
</div> </div>
<div class="col-md-5 col-sm-6 col-xs-4"> <div class="col-md-5 col-sm-6 col-xs-4">
<br/> <br />
<img style="height:75px;" ng-src="{{Authors.headshot}}" /> <img style="height: 75px" ng-src="{{Authors.headshot}}" />
</div> </div>
</div> </div>
</div> </div>
<form class="form-horizontal" name="newAuthors" ng-submit="Authors.upsert(Authors.selectedAuthor)"> <form
class="form-horizontal"
name="newAuthors"
ng-submit="Authors.upsert(Authors.selectedAuthor)"
>
<div class="row"> <div class="row">
<div class="col-sm-8"> <div class="col-sm-8">
<small><span ng-bind="Authors.blogdir" <small
></span>/authors/<span ng-bind="Authors.selectedAuthor.handle" ><span ng-bind="Authors.blogdir"></span>/authors/<span
></span><span ng-if="Authors.selectedAuthor.handle" ng-bind="Authors.selectedAuthor.handle"
>.yml</span></small> ></span
><span ng-if="Authors.selectedAuthor.handle">.yml</span></small
>
</div> </div>
<div class="col-sm-4"> <div class="col-sm-4">
<button class="btn btn-success pull-right" type="submit" ng-disabled="Authors.dirty || !Authors.selectedAuthor.handle">Save &amp; Continue</button> <button
class="btn btn-success pull-right"
type="submit"
ng-disabled="Authors.dirty || !Authors.selectedAuthor.handle"
>
Save &amp; Continue
</button>
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<br/> <br />
</div> </div>
<div class="row"> <div class="row">
<div class="col-lg-12"> <div class="col-lg-12">
@ -47,97 +58,138 @@
<fieldset> <fieldset>
<legend>Profile Basics</legend> <legend>Profile Basics</legend>
<div class="row"> <div class="row">
<div class="col-md-6"> <div class="col-md-6">
<div class="form-group"> <div class="form-group">
<label for="inputAuthorName" class="col-lg-4 control-label">Name*</label> <label for="inputAuthorName" class="col-lg-4 control-label"
<div class="col-lg-8"> >Name*</label
<input ng-model="Authors.selectedAuthor.name"
required="required"
type="text"
class="form-control"
id="inputAuthorName"
name="inputAuthorName"
placeholder="i.e. John Doe">
</div>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="inputAuthorNickname" class="col-lg-4 control-label">Handle*</label>
<div class="col-lg-8">
<input ng-model="Authors.selectedAuthor.handle"
required="required"
type="text"
class="form-control"
id="inputAuthorNickname"
name="inputAuthorNickname"
placeholder="i.e. johndoe">
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label for="inputAuthorEmail" class="col-lg-4 control-label">Email*</label>
<div class="col-lg-8">
<input ng-model="Authors.selectedAuthor.email" ng-change="Authors.updateHeadshotUrl()"
required="required"
type="email"
class="form-control"
id="inputAuthorEmail"
name="inputAuthorEmail"
placeholder="i.e. john.doe@gmail.com">
</div>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="inputAuthorWebsite" class="col-lg-4 control-label">Website</label>
<div class="col-lg-8">
<input ng-model="Authors.selectedAuthor.website"
type="url"
class="form-control"
id="inputAuthorWebsite"
name="inputAuthorWebsite"
placeholder="i.e. http://johndoe.name"
> >
<div class="col-lg-8">
<input
ng-model="Authors.selectedAuthor.name"
required="required"
type="text"
class="form-control"
id="inputAuthorName"
name="inputAuthorName"
placeholder="i.e. John Doe"
/>
</div>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label
for="inputAuthorNickname"
class="col-lg-4 control-label"
>Handle*</label
>
<div class="col-lg-8">
<input
ng-model="Authors.selectedAuthor.handle"
required="required"
type="text"
class="form-control"
id="inputAuthorNickname"
name="inputAuthorNickname"
placeholder="i.e. johndoe"
/>
</div>
</div>
</div> </div>
</div> </div>
</div>
</div>
<div class="row"> <div class="row">
<div class="col-lg-12"> <div class="col-md-6">
<div class="form-group"> <div class="form-group">
<label for="inputAuthorBio" class="col-lg-2 control-label">Bio <label for="inputAuthorEmail" class="col-lg-4 control-label"
<small>(<span ng-bind="Authors.selectedAuthor.bio.length || 0"></span>/140)</small></label> >Email*</label
<div class="col-lg-10"> >
<textarea ng-model="Authors.selectedAuthor.bio" <div class="col-lg-8">
class="form-control" id="inputAuthorBio" placeholder="i.e. Brogrammatic Ninja-throwing Rockstar Badassian Wizard JavaScript Superstar. 3+ years experience as a jalapeno poppers brony. YOLO."></textarea> <input
ng-model="Authors.selectedAuthor.email"
ng-change="Authors.updateHeadshotUrl()"
required="required"
type="email"
class="form-control"
id="inputAuthorEmail"
name="inputAuthorEmail"
placeholder="i.e. john.doe@gmail.com"
/>
</div>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="inputAuthorWebsite" class="col-lg-4 control-label"
>Website</label
>
<div class="col-lg-8">
<input
ng-model="Authors.selectedAuthor.website"
type="url"
class="form-control"
id="inputAuthorWebsite"
name="inputAuthorWebsite"
placeholder="i.e. http://johndoe.name"
/>
</div>
</div>
</div> </div>
</div> </div>
</div>
</div>
<div class="row"> <div class="row">
<div class="col-lg-12"> <div class="col-lg-12">
<div class="form-group"> <div class="form-group">
<label for="inputAuthorHeadshot" class="col-lg-2 control-label">Headshot</label> <label for="inputAuthorBio" class="col-lg-2 control-label"
<div class="col-lg-10"> >Bio
<input ng-model="Authors.selectedAuthor.headshot" ng-change="Authors.updateHeadshotUrl()" <small
type="text" class="form-control" id="inputAuthorHeadshot" placeholder="i.e. https://i.imgur.com/qqpxDmJ.jpg"> >(<span
<span class="help-block">Hint: Link your photo to your email on <a href="https://gravatar.com">Gravatar</a> or upload to <a href="https://imgur.com">imgur</a>.</span> ng-bind="Authors.selectedAuthor.bio.length || 0"
></span
>/140)</small
></label
>
<div class="col-lg-10">
<textarea
ng-model="Authors.selectedAuthor.bio"
class="form-control"
id="inputAuthorBio"
placeholder="i.e. Brogrammatic Ninja-throwing Rockstar Badassian Wizard JavaScript Superstar. 3+ years experience as a jalapeno poppers brony. YOLO."
></textarea>
</div>
</div>
</div> </div>
</div> </div>
</div>
</div>
<div class="row">
<div class="col-lg-12">
<div class="form-group">
<label
for="inputAuthorHeadshot"
class="col-lg-2 control-label"
>Headshot</label
>
<div class="col-lg-10">
<input
ng-model="Authors.selectedAuthor.headshot"
ng-change="Authors.updateHeadshotUrl()"
type="text"
class="form-control"
id="inputAuthorHeadshot"
placeholder="i.e. https://i.imgur.com/qqpxDmJ.jpg"
/>
<span class="help-block"
>Hint: Link your photo to your email on
<a href="https://gravatar.com">Gravatar</a> or upload to
<a href="https://imgur.com">imgur</a>.</span
>
</div>
</div>
</div>
</div>
</fieldset> </fieldset>
</div> </div>
</div> </div>
@ -148,26 +200,47 @@
<legend>Social</legend> <legend>Social</legend>
<div class="form-group"> <div class="form-group">
<label for="inputAuthorTwitter" class="col-lg-2 control-label">Twitter</label> <label for="inputAuthorTwitter" class="col-lg-2 control-label"
>Twitter</label
>
<div class="col-lg-10"> <div class="col-lg-10">
<input ng-model="Authors.selectedAuthor.twitter" <input
type="text" class="form-control" id="inputAuthorTwitter" placeholder="i.e. @johndoe"> ng-model="Authors.selectedAuthor.twitter"
type="text"
class="form-control"
id="inputAuthorTwitter"
placeholder="i.e. @johndoe"
/>
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="inputAuthorFacebook" class="col-lg-2 control-label">Facebook URL</label> <label for="inputAuthorFacebook" class="col-lg-2 control-label"
>Facebook URL</label
>
<div class="col-lg-10"> <div class="col-lg-10">
<input ng-model="Authors.selectedAuthor.facebook" <input
type="text" class="form-control" id="inputAuthorFacebook" placeholder="i.e. facebook.com/johndoe"> ng-model="Authors.selectedAuthor.facebook"
type="text"
class="form-control"
id="inputAuthorFacebook"
placeholder="i.e. facebook.com/johndoe"
/>
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="inputAuthorGooglePlus" class="col-lg-2 control-label">Google+ URL</label> <label for="inputAuthorGooglePlus" class="col-lg-2 control-label"
>Google+ URL</label
>
<div class="col-lg-10"> <div class="col-lg-10">
<input ng-model="Authors.selectedAuthor.googleplus" <input
type="text" class="form-control" id="inputAuthorGooglePlus" placeholder="i.e. plus.google.com/+johndoe"> ng-model="Authors.selectedAuthor.googleplus"
type="text"
class="form-control"
id="inputAuthorGooglePlus"
placeholder="i.e. plus.google.com/+johndoe"
/>
</div> </div>
</div> </div>
</fieldset> </fieldset>
@ -179,21 +252,36 @@
<fieldset> <fieldset>
<legend>Developers</legend> <legend>Developers</legend>
<div class="form-group"> <div class="form-group">
<label for="inputAuthorGithub" class="col-lg-2 control-label">Github</label> <label for="inputAuthorGithub" class="col-lg-2 control-label"
>Github</label
>
<div class="col-lg-10"> <div class="col-lg-10">
<input ng-model="Authors.selectedAuthor.github" <input
type="text" class="form-control" id="inputAuthorGithub" placeholder="i.e. johndoe"> ng-model="Authors.selectedAuthor.github"
type="text"
class="form-control"
id="inputAuthorGithub"
placeholder="i.e. johndoe"
/>
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="inputAuthorStackOverflow" class="col-lg-2 control-label">StackOverflow</label> <label
for="inputAuthorStackOverflow"
class="col-lg-2 control-label"
>StackOverflow</label
>
<div class="col-lg-10"> <div class="col-lg-10">
<input ng-model="Authors.selectedAuthor.stackoverflow" <input
type="text" class="form-control" id="inputAuthorStackOverflow" placeholder="i.e. http://stackoverflow.com/users/151312/johndoe"> ng-model="Authors.selectedAuthor.stackoverflow"
type="text"
class="form-control"
id="inputAuthorStackOverflow"
placeholder="i.e. http://stackoverflow.com/users/151312/johndoe"
/>
</div> </div>
</div> </div>
</fieldset>
</fieldset>
</div> </div>
</div> </div>
@ -203,19 +291,26 @@
<legend>Feeds</legend> <legend>Feeds</legend>
<div class="form-group"> <div class="form-group">
<label for="inputAuthorFeedburner" class="col-lg-2 control-label">Feedburner</label> <label for="inputAuthorFeedburner" class="col-lg-2 control-label"
>Feedburner</label
>
<div class="col-lg-10"> <div class="col-lg-10">
<input ng-model="Authors.selectedAuthor.feedburner" <input
type="text" class="form-control" id="inputAuthorFeedburner" placeholder="i.e. johndoe"> ng-model="Authors.selectedAuthor.feedburner"
type="text"
class="form-control"
id="inputAuthorFeedburner"
placeholder="i.e. johndoe"
/>
</div> </div>
</div> </div>
</fieldset> </fieldset>
</div> </div>
</div> </div>
<button class="btn btn-primary pull-right" type="submit">Save &amp; Continue</button> <button class="btn btn-primary pull-right" type="submit">
Save &amp; Continue
</button>
</div> </div>
</form> </form>
</div> </div>

View File

@ -1,113 +1,134 @@
'use strict'; "use strict";
angular.module('myApp.authors', ['ngRoute']) angular
.module("myApp.authors", ["ngRoute"])
.config(['$routeProvider', function($routeProvider) { .config([
$routeProvider.when('/authors', { "$routeProvider",
templateUrl: 'views/authors/authors.html', function ($routeProvider) {
controller: 'AuthorsCtrl as Authors' $routeProvider.when("/authors", {
}); templateUrl: "views/authors/authors.html",
}]) controller: "AuthorsCtrl as Authors",
.controller('AuthorsCtrl'
, ['$scope', '$timeout', '$location', 'Desirae'
, function($scope, $timeout, $location, Desirae) {
var scope = this
;
scope.newAuthor = function () {
console.log('new author');
scope.new = { filename: 'new' };
scope.selectAuthor(scope.new);
};
scope.selectAuthor = function (author) {
// TODO watch any change
scope.selectedAuthor = author || scope.selectedAuthor;
scope.updateHeadshotUrlNow();
};
scope.upsert = function () {
var author = scope.selectedAuthor
, files = []
, filename = author.filename
;
delete author.filename;
if ('new' !== filename && filename !== author.handle) {
files.push({ path: 'authors/' + filename + '.yml', contents: '', delete: true });
}
files.push({ path: 'authors/' + author.handle + '.yml', contents: window.jsyaml.dump(author) });
console.log(files);
Desirae.putFiles(files).then(function (results) {
console.log('updated author', results);
$location.path('/site');
}).catch(function (e) {
author.filename = filename;
console.error(e);
window.alert("Error Nation! :/");
throw e;
});
};
scope.updateHeadshotUrlNow = function () {
var gravatar = 'http://www.gravatar.com/avatar/' + window.md5((scope.selectedAuthor.email||'foo').toLowerCase()) + '?d=identicon'
;
if (scope.selectedAuthor.headshot) {
scope.headshot = scope.selectedAuthor.headshot;
}
else if (scope.selectedAuthor.email) {
scope.headshot = gravatar;
}
else {
scope.headshot = 'http://www.gravatar.com/avatar/' + window.md5((scope.selectedAuthor.email||'foo').toLowerCase()) + '?d=mm';
}
};
scope.updateHeadshotUrl = function () {
$timeout.cancel(scope.hslock);
scope.hslock = $timeout(function () {
scope.updateHeadshotUrlNow();
}, 300);
};
function init() {
scope.newAuthor();
console.log('desi loading');
Desirae.meta().then(function (desi) {
var filename
;
scope.blogdir = desi.blogdir.path.replace(/^\/(Users|home)\/[^\/]+\//, '~/');
desi.authors = desi.authors || {};
desi.authors.new = scope.new;
scope.authors = desi.authors;
Object.keys(desi.authors).forEach(function (filename) {
if ('new' === filename) {
return;
}
desi.authors[filename].filename = filename;
desi.authors[filename].handle = desi.authors[filename].handle || filename;
}); });
},
])
filename = Object.keys(desi.authors)[0]; .controller("AuthorsCtrl", [
scope.selectedAuthor = desi.authors[filename]; "$scope",
"$timeout",
"$location",
"Desirae",
function ($scope, $timeout, $location, Desirae) {
var scope = this;
scope.newAuthor = function () {
console.log("new author");
scope.new = { filename: "new" };
scope.selectAuthor(scope.new);
};
scope.updateHeadshotUrlNow(); scope.selectAuthor = function (author) {
}).catch(function (e) { // TODO watch any change
window.alert("An Error Occured. Most errors that occur in the init phase are parse errors in the config files or permissions errors on files or directories, but check the error console for details."); scope.selectedAuthor = author || scope.selectedAuthor;
console.error(e); scope.updateHeadshotUrlNow();
throw e; };
});
}
init(); scope.upsert = function () {
/* var author = scope.selectedAuthor,
files = [],
filename = author.filename;
delete author.filename;
if ("new" !== filename && filename !== author.handle) {
files.push({
path: "authors/" + filename + ".yml",
contents: "",
delete: true,
});
}
files.push({
path: "authors/" + author.handle + ".yml",
contents: window.jsyaml.dump(author),
});
console.log(files);
Desirae.putFiles(files)
.then(function (results) {
console.log("updated author", results);
$location.path("/site");
})
.catch(function (e) {
author.filename = filename;
console.error(e);
window.alert("Error Nation! :/");
throw e;
});
};
scope.updateHeadshotUrlNow = function () {
var gravatar =
"http://www.gravatar.com/avatar/" +
window.md5((scope.selectedAuthor.email || "foo").toLowerCase()) +
"?d=identicon";
if (scope.selectedAuthor.headshot) {
scope.headshot = scope.selectedAuthor.headshot;
} else if (scope.selectedAuthor.email) {
scope.headshot = gravatar;
} else {
scope.headshot =
"http://www.gravatar.com/avatar/" +
window.md5((scope.selectedAuthor.email || "foo").toLowerCase()) +
"?d=mm";
}
};
scope.updateHeadshotUrl = function () {
$timeout.cancel(scope.hslock);
scope.hslock = $timeout(function () {
scope.updateHeadshotUrlNow();
}, 300);
};
function init() {
scope.newAuthor();
console.log("desi loading");
Desirae.meta()
.then(function (desi) {
var filename;
scope.blogdir = desi.blogdir.path.replace(
/^\/(Users|home)\/[^\/]+\//,
"~/"
);
desi.authors = desi.authors || {};
desi.authors.new = scope.new;
scope.authors = desi.authors;
Object.keys(desi.authors).forEach(function (filename) {
if ("new" === filename) {
return;
}
desi.authors[filename].filename = filename;
desi.authors[filename].handle =
desi.authors[filename].handle || filename;
});
filename = Object.keys(desi.authors)[0];
scope.selectedAuthor = desi.authors[filename];
scope.updateHeadshotUrlNow();
})
.catch(function (e) {
window.alert(
"An Error Occured. Most errors that occur in the init phase are parse errors in the config files or permissions errors on files or directories, but check the error console for details."
);
console.error(e);
throw e;
});
}
init();
/*
$scope.$watch(angular.bind(this, function () { return this.selectedAuthor; }), function (newValue, oldValue) { $scope.$watch(angular.bind(this, function () { return this.selectedAuthor; }), function (newValue, oldValue) {
//$scope.$watch('Authors.selecteAuthor', function (newValue, oldValue) //$scope.$watch('Authors.selecteAuthor', function (newValue, oldValue)
console.log(newValue, oldValue); console.log(newValue, oldValue);
@ -116,4 +137,5 @@ angular.module('myApp.authors', ['ngRoute'])
} }
}, true); }, true);
*/ */
}]); },
]);

View File

@ -3,7 +3,7 @@
<div class="row"> <div class="row">
<div class="page-header"> <div class="page-header">
<h1>Build Static Site</h1> <h1>Build Static Site</h1>
<h3><span ng-bind="Build.blogdir"></span></h3> <h3><span ng-bind="Build.blogdir"></span></h3>
</div> </div>
</div> </div>
@ -11,16 +11,27 @@
<div class="col-lg-12"> <div class="col-lg-12">
<h2>Are you ready?</h2> <h2>Are you ready?</h2>
<p> <p>
<small><a href="https://www.youtube.com/watch?v=-E0oiKjLzTc" target="_blank">Bonesaw</a> is READY!</small> <small
><a
href="https://www.youtube.com/watch?v=-E0oiKjLzTc"
target="_blank"
>Bonesaw</a
>
is READY!</small
>
</p> </p>
<p> <p>
<button <button
ng-click="Build.build(['production', 'development'])" ng-click="Build.build(['production', 'development'])"
class="btn btn-danger" class="btn btn-danger"
type="button" type="button"
>Build Sites</button> >
Build Sites
</button>
</p> </p>
<span class="help-block">Push the RED button... you know you want to!</span> <span class="help-block"
>Push the RED button... you know you want to!</span
>
</div> </div>
</div> </div>
@ -29,28 +40,42 @@
<div class="well bs-component"> <div class="well bs-component">
<fieldset> <fieldset>
<legend>Production</legend> <legend>Production</legend>
<p><a ng-href="{{Build.display_url}}" target="_blank"><span ng-bind="Build.display_url"></span></a></p> <p>
<a ng-href="{{Build.display_url}}" target="_blank"
><span ng-bind="Build.display_url"></span
></a>
</p>
<div class="form-group"> <div class="form-group">
<label for="inputProdCanonicalUrl" class="col-lg-2 control-label">Canonical URL</label> <label for="inputProdCanonicalUrl" class="col-lg-2 control-label"
>Canonical URL</label
>
<div class="col-lg-10"> <div class="col-lg-10">
<input ng-model="Build.production_url" <input
ng-model="Build.production_url"
required="required" required="required"
placeholder="i.e. https://example.com/myblog" placeholder="i.e. https://example.com/myblog"
type="url" type="url"
class="form-control" class="form-control"
id="inputProdCanonicalUrl"> id="inputProdCanonicalUrl"
<br/> />
<br />
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="inputProdOutput" class="col-lg-2 control-label">Output Path</label> <label for="inputProdOutput" class="col-lg-2 control-label"
>Output Path</label
>
<div class="col-lg-10"> <div class="col-lg-10">
<input <input
disabled disabled
ng-value="Build.blogdir + '/compiled'" ng-value="Build.blogdir + '/compiled'"
type="text" class="form-control" id="inputProdOutput" disabled> type="text"
class="form-control"
id="inputProdOutput"
disabled
/>
</div> </div>
</div> </div>
@ -63,7 +88,9 @@
ng-click="Build.build(['production'])" ng-click="Build.build(['production'])"
class="btn btn-primary pull-right" class="btn btn-primary pull-right"
type="button" type="button"
>Build Production Site</button> >
Build Production Site
</button>
</div> </div>
</div> </div>
</fieldset> </fieldset>
@ -71,10 +98,16 @@
<div class="well bs-component"> <div class="well bs-component">
<fieldset> <fieldset>
<legend>Development</legend> <legend>Development</legend>
<p><a ng-href="{{Build.development_url}}" target="_blank"><span ng-bind="Build.development_url"></span></a></p> <p>
<a ng-href="{{Build.development_url}}" target="_blank"
><span ng-bind="Build.development_url"></span
></a>
</p>
<div class="form-group"> <div class="form-group">
<label for="inputDevCanonicalUrl" class="col-lg-2 control-label">Canonical URL</label> <label for="inputDevCanonicalUrl" class="col-lg-2 control-label"
>Canonical URL</label
>
<div class="col-lg-10"> <div class="col-lg-10">
<input <input
ng-model="Build.development_url" ng-model="Build.development_url"
@ -83,18 +116,25 @@
placeholder="i.e. https://example.com/myblog" placeholder="i.e. https://example.com/myblog"
type="url" type="url"
class="form-control" class="form-control"
id="inputDevCanonicalUrl"> id="inputDevCanonicalUrl"
<br/> />
<br />
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="inputDevOutput" class="col-lg-2 control-label">Output Path</label> <label for="inputDevOutput" class="col-lg-2 control-label"
>Output Path</label
>
<div class="col-lg-10"> <div class="col-lg-10">
<input <input
disabled disabled
ng-value="Build.blogdir + '/compiled_dev'" ng-value="Build.blogdir + '/compiled_dev'"
type="text" class="form-control" id="inputDevOutput" disabled> type="text"
class="form-control"
id="inputDevOutput"
disabled
/>
</div> </div>
</div> </div>
@ -107,13 +147,14 @@
ng-click="Build.build(['development'])" ng-click="Build.build(['development'])"
class="btn btn-primary pull-right" class="btn btn-primary pull-right"
type="button" type="button"
>Build Development Site</button> >
Build Development Site
</button>
</div> </div>
</div> </div>
</fieldset> </fieldset>
</div> </div>
</div> </div>
</div> </div>
</form> </form>
</div> </div>

View File

@ -1,100 +1,135 @@
'use strict'; "use strict";
angular.module('myApp.build', ['ngRoute']) angular
.module("myApp.build", ["ngRoute"])
.config(['$routeProvider', function($routeProvider) { .config([
$routeProvider.when('/build', { "$routeProvider",
templateUrl: 'views/build/build.html', function ($routeProvider) {
controller: 'BuildCtrl as Build' $routeProvider.when("/build", {
}); templateUrl: "views/build/build.html",
}]) controller: "BuildCtrl as Build",
.controller('BuildCtrl'
, ['$scope', '$location', '$timeout', 'Desirae'
, function ($scope, $location, $timeout, DesiraeService) {
var scope = this
, path = window.path
;
function init() {
scope.extensions = ['md', 'html'];
return DesiraeService.meta().then(function (desi) {
scope.blogdir = desi.blogdir.path.replace(/^\/(Users|home)\/[^\/]+\//, '~/');
scope.site = desi.site;
if (!desi.site.base_url || !desi.site.base_path) {
window.alert("Please go back to the site config and enter any mandatory missing fields (base_url, base_path).");
return;
}
scope.display_url = scope.production_url = desi.site.base_url + path.join('/', desi.site.base_path);
if (/dropbox/.test(scope.display_url)) {
scope.display_url += '/index.html';
}
// this is the responsibility of the build system (Dear Desi), not the library (Desirae)
scope.development_url = location.href.replace(/\/(#.*)?$/, '') + path.join('/', 'compiled_dev');
return desi;
}).catch(function (e) {
window.alert("An Error Occured. Most errors that occur in the init phase are parse errors in the config files or permissions errors on files or directories, but check the error console for details.");
console.error(e);
throw e;
});
}
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();
}
};
scope.buildOne = function (envstr) {
return DesiraeService.reset().then(function () {
return init().then(function () {
var env
;
// 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.production_url.replace(/(https?:\/\/[^\/#?]+).*/, '$1')
, base_path: scope.production_url.replace(/https?:\/\/[^\/#?]+/, '')
, 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
};
}
return DesiraeService.build(env).then(function () {
DesiraeService.write(env);
});
}); });
}); },
}; ])
scope.build = function (envs) { .controller("BuildCtrl", [
window.forEachAsync(envs, function (env) { "$scope",
return scope.buildOne(env); "$location",
}).then(function () { "$timeout",
window.alert('Build(s) Complete'); "Desirae",
}); function ($scope, $location, $timeout, DesiraeService) {
}; var scope = this,
path = window.path;
function init() {
scope.extensions = ["md", "html"];
init(); return DesiraeService.meta()
}]); .then(function (desi) {
scope.blogdir = desi.blogdir.path.replace(
/^\/(Users|home)\/[^\/]+\//,
"~/"
);
scope.site = desi.site;
if (!desi.site.base_url || !desi.site.base_path) {
window.alert(
"Please go back to the site config and enter any mandatory missing fields (base_url, base_path)."
);
return;
}
scope.display_url = scope.production_url =
desi.site.base_url + path.join("/", desi.site.base_path);
if (/dropbox/.test(scope.display_url)) {
scope.display_url += "/index.html";
}
// this is the responsibility of the build system (Dear Desi), not the library (Desirae)
scope.development_url =
location.href.replace(/\/(#.*)?$/, "") +
path.join("/", "compiled_dev");
return desi;
})
.catch(function (e) {
window.alert(
"An Error Occured. Most errors that occur in the init phase are parse errors in the config files or permissions errors on files or directories, but check the error console for details."
);
console.error(e);
throw e;
});
}
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();
}
};
scope.buildOne = function (envstr) {
return DesiraeService.reset().then(function () {
return init().then(function () {
var env;
// 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.production_url.replace(
/(https?:\/\/[^\/#?]+).*/,
"$1"
),
base_path: scope.production_url.replace(
/https?:\/\/[^\/#?]+/,
""
),
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,
};
}
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");
});
};
init();
},
]);

View File

@ -14,9 +14,16 @@
<legend>Advanced</legend> <legend>Advanced</legend>
<div class="form-group"> <div class="form-group">
<label for="inputRootConf" class="col-lg-2 control-label">Root Pages</label> <label for="inputRootConf" class="col-lg-2 control-label"
>Root Pages</label
>
<div class="col-lg-8"> <div class="col-lg-8">
<input type="text" class="form-control" id="inputRootConf" placeholder="i.e. images"> <input
type="text"
class="form-control"
id="inputRootConf"
placeholder="i.e. images"
/>
</div> </div>
<div class="col-lg-2"> <div class="col-lg-2">
<button class="btn" type="button">Add</button> <button class="btn" type="button">Add</button>
@ -24,9 +31,16 @@
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="inputThemesConf" class="col-lg-2 control-label">Themes</label> <label for="inputThemesConf" class="col-lg-2 control-label"
>Themes</label
>
<div class="col-lg-8"> <div class="col-lg-8">
<input type="text" class="form-control" id="inputThemesConf" placeholder="i.e. images"> <input
type="text"
class="form-control"
id="inputThemesConf"
placeholder="i.e. images"
/>
</div> </div>
<div class="col-lg-2"> <div class="col-lg-2">
<button class="btn" type="button">Add</button> <button class="btn" type="button">Add</button>
@ -34,9 +48,16 @@
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="inputCollectionsConf" class="col-lg-2 control-label">Collections</label> <label for="inputCollectionsConf" class="col-lg-2 control-label"
>Collections</label
>
<div class="col-lg-8"> <div class="col-lg-8">
<input type="text" class="form-control" id="inputCollectionsConf" placeholder="i.e. images"> <input
type="text"
class="form-control"
id="inputCollectionsConf"
placeholder="i.e. images"
/>
</div> </div>
<div class="col-lg-2"> <div class="col-lg-2">
<button class="btn" type="button">Add</button> <button class="btn" type="button">Add</button>
@ -44,9 +65,16 @@
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="inputAssetsConf" class="col-lg-2 control-label">Assets</label> <label for="inputAssetsConf" class="col-lg-2 control-label"
>Assets</label
>
<div class="col-lg-8"> <div class="col-lg-8">
<input type="text" class="form-control" id="inputAssetsConf" placeholder="i.e. images"> <input
type="text"
class="form-control"
id="inputAssetsConf"
placeholder="i.e. images"
/>
</div> </div>
<div class="col-lg-2"> <div class="col-lg-2">
<button class="btn" type="button">Add</button> <button class="btn" type="button">Add</button>
@ -54,19 +82,24 @@
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="inputWidgetsConf" class="col-lg-2 control-label">Widgets</label> <label for="inputWidgetsConf" class="col-lg-2 control-label"
>Widgets</label
>
<div class="col-lg-8"> <div class="col-lg-8">
<input type="text" class="form-control" id="inputWidgetsConf" placeholder="i.e. images"> <input
type="text"
class="form-control"
id="inputWidgetsConf"
placeholder="i.e. images"
/>
</div> </div>
<div class="col-lg-2"> <div class="col-lg-2">
<button class="btn" type="button">Add</button> <button class="btn" type="button">Add</button>
</div> </div>
</div> </div>
</fieldset>
</fieldset>
</div> </div>
</div> </div>
</div> </div>
</form> </form>
</div> </div>

View File

@ -1,13 +1,16 @@
'use strict'; "use strict";
angular.module('myApp.configure', ['ngRoute']) angular
.module("myApp.configure", ["ngRoute"])
.config(['$routeProvider', function($routeProvider) { .config([
$routeProvider.when('/configure', { "$routeProvider",
templateUrl: 'views/configure/configure.html', function ($routeProvider) {
controller: 'ConfigureCtrl as Configure' $routeProvider.when("/configure", {
}); templateUrl: "views/configure/configure.html",
}]) controller: "ConfigureCtrl as Configure",
});
},
])
.controller('ConfigureCtrl', [function() { .controller("ConfigureCtrl", [function () {}]);
}]);

View File

@ -11,27 +11,48 @@
<div class="well bs-component"> <div class="well bs-component">
<fieldset> <fieldset>
<div class="form-group"> <div class="form-group">
<label for="inputEmail" class="col-lg-2 control-label">Email</label> <label for="inputEmail" class="col-lg-2 control-label"
>Email</label
>
<div class="col-lg-10"> <div class="col-lg-10">
<input type="text" class="form-control" id="inputEmail" placeholder="Email"> <input
type="text"
class="form-control"
id="inputEmail"
placeholder="Email"
/>
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="inputPassword" class="col-lg-2 control-label">Password</label> <label for="inputPassword" class="col-lg-2 control-label"
>Password</label
>
<div class="col-lg-10"> <div class="col-lg-10">
<input type="password" class="form-control" id="inputPassword" placeholder="Password"> <input
type="password"
class="form-control"
id="inputPassword"
placeholder="Password"
/>
<div class="checkbox"> <div class="checkbox">
<label> <label> <input type="checkbox" /> Checkbox </label>
<input type="checkbox"> Checkbox
</label>
</div> </div>
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="textArea" class="col-lg-2 control-label">Textarea</label> <label for="textArea" class="col-lg-2 control-label"
>Textarea</label
>
<div class="col-lg-10"> <div class="col-lg-10">
<textarea class="form-control" rows="3" id="textArea"></textarea> <textarea
<span class="help-block">A longer block of help text that breaks onto a new line and may extend beyond one line.</span> class="form-control"
rows="3"
id="textArea"
></textarea>
<span class="help-block"
>A longer block of help text that breaks onto a new line and
may extend beyond one line.</span
>
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
@ -39,13 +60,24 @@
<div class="col-lg-10"> <div class="col-lg-10">
<div class="radio"> <div class="radio">
<label> <label>
<input type="radio" name="optionsRadios" id="optionsRadios1" value="option1" checked=""> <input
type="radio"
name="optionsRadios"
id="optionsRadios1"
value="option1"
checked=""
/>
Option one is this Option one is this
</label> </label>
</div> </div>
<div class="radio"> <div class="radio">
<label> <label>
<input type="radio" name="optionsRadios" id="optionsRadios2" value="option2"> <input
type="radio"
name="optionsRadios"
id="optionsRadios2"
value="option2"
/>
Option two can be something else Option two can be something else
</label> </label>
</div> </div>
@ -61,7 +93,7 @@
<option>4</option> <option>4</option>
<option>5</option> <option>5</option>
</select> </select>
<br> <br />
<select multiple="" class="form-control"> <select multiple="" class="form-control">
<option>1</option> <option>1</option>
<option>2</option> <option>2</option>
@ -78,6 +110,15 @@
</div> </div>
</div> </div>
</fieldset> </fieldset>
<div id="source-button" class="btn btn-primary btn-xs" style="display: none;">&lt; &gt;</div></div> <div
id="source-button"
class="btn btn-primary btn-xs"
style="display: none"
>
&lt; &gt;
</div>
</div>
</div> </div>
</div>
</form>
</div>

View File

@ -3,7 +3,7 @@
<div class="row"> <div class="row">
<div class="page-header"> <div class="page-header">
<h1>Write a Post</h1> <h1>Write a Post</h1>
<h3><span ng-bind="Post.selected.post.yml.permalink" ></span></h3> <h3><span ng-bind="Post.selected.post.yml.permalink"></span></h3>
</div> </div>
</div> </div>
@ -12,7 +12,9 @@
<div class="well bs-component"> <div class="well bs-component">
<fieldset> <fieldset>
<div class="form-group"> <div class="form-group">
<label for="inputPostTitle" class="col-lg-2 control-label">Title*</label> <label for="inputPostTitle" class="col-lg-2 control-label"
>Title*</label
>
<div class="col-lg-10"> <div class="col-lg-10">
<input <input
required="required" required="required"
@ -22,7 +24,7 @@
class="form-control" class="form-control"
id="inputPostTitle" id="inputPostTitle"
placeholder="i.e. My First Post" placeholder="i.e. My First Post"
> />
</div> </div>
</div> </div>
<!-- <!--
@ -40,7 +42,9 @@
</div> </div>
--> -->
<div class="form-group"> <div class="form-group">
<label for="textAreaPost" class="col-lg-2 control-label">Post*</label> <label for="textAreaPost" class="col-lg-2 control-label"
>Post*</label
>
<div class="col-lg-10"> <div class="col-lg-10">
<textarea <textarea
required="required" required="required"
@ -50,8 +54,10 @@
rows="20" rows="20"
id="textAreaPost" id="textAreaPost"
placeholder="i.e. I Don't Know Anything About the Gold Standard... But I Do Love Little Kittens!" placeholder="i.e. I Don't Know Anything About the Gold Standard... But I Do Love Little Kittens!"
></textarea> ></textarea>
<span class="help-block">Put your lovely post here, in github-flavored markdown!</span> <span class="help-block"
>Put your lovely post here, in github-flavored markdown!</span
>
</div> </div>
</div> </div>
@ -63,10 +69,13 @@
ng-model="Post.selected.format" ng-model="Post.selected.format"
ng-change="Post.onChange()" ng-change="Post.onChange()"
class="form-control" class="form-control"
id="select"> id="select"
>
<option value="html">HTML</option> <option value="html">HTML</option>
<option selected="selected" value="md">Markdown</option> <option selected="selected" value="md">Markdown</option>
<option disabled="disabled" value="jade">Jade (Not Implemented)</option> <option disabled="disabled" value="jade">
Jade (Not Implemented)
</option>
</select> </select>
<!--div class="checkbox"> <!--div class="checkbox">
<label> <label>
@ -77,35 +86,51 @@
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="textAreaDesc" class="col-lg-2 control-label">Description <label for="textAreaDesc" class="col-lg-2 control-label"
<small>(<span ng-bind="Post.selected.post.yml.description.length || 0"></span>/140)</small></label> >Description
<small
>(<span
ng-bind="Post.selected.post.yml.description.length || 0"
></span
>/140)</small
></label
>
<div class="col-lg-10"> <div class="col-lg-10">
<textarea <textarea
ng-change="Post.onChange()" ng-change="Post.onChange()"
ng-model="Post.selected.post.yml.description" ng-model="Post.selected.post.yml.description"
placeholder="i.e. An alternate recipe for Peeta Mellarks's famous apple goat cheese tarts using only ingredients available in district 10" placeholder="i.e. An alternate recipe for Peeta Mellarks's famous apple goat cheese tarts using only ingredients available in district 10"
class="form-control" class="form-control"
rows="2" rows="2"
id="textAreaDesc"></textarea> id="textAreaDesc"
<span class="help-block">The description is often used by search engines as the snippit shown in search results.</span> ></textarea>
<span class="help-block"
>The description is often used by search engines as the
snippit shown in search results.</span
>
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="textAreaYaml" class="col-lg-2 control-label">Frontmatter</label> <label for="textAreaYaml" class="col-lg-2 control-label"
>Frontmatter</label
>
<div class="col-lg-10"> <div class="col-lg-10">
<textarea <textarea
required="required" required="required"
ng-change="Post.onFrontmatterChange()" ng-change="Post.onFrontmatterChange()"
ng-model="Post.selected.post.frontmatter" ng-model="Post.selected.post.frontmatter"
class="form-control" class="form-control"
rows="5" rows="5"
id="textAreaYaml"></textarea> id="textAreaYaml"
></textarea>
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="inputPostAbsPath" class="col-lg-2 control-label">Source Path</label> <label for="inputPostAbsPath" class="col-lg-2 control-label"
>Source Path</label
>
<div class="col-lg-10"> <div class="col-lg-10">
<input <input
required="required" required="required"
@ -116,12 +141,14 @@
class="form-control" class="form-control"
id="inputPostAbsPath" id="inputPostAbsPath"
placeholder="i.e. ~/blog.me.co/posts/my-first-post.md" placeholder="i.e. ~/blog.me.co/posts/my-first-post.md"
> />
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="inputPostAbsPath" class="col-lg-2 control-label">Output Path</label> <label for="inputPostAbsPath" class="col-lg-2 control-label"
>Output Path</label
>
<div class="col-lg-10"> <div class="col-lg-10">
<input <input
required="required" required="required"
@ -132,18 +159,21 @@
class="form-control" class="form-control"
id="inputPostAbsPath" id="inputPostAbsPath"
placeholder="i.e. ~/blog.me.co/posts/my-first-post.md" placeholder="i.e. ~/blog.me.co/posts/my-first-post.md"
> />
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="inputPostAbsPath" class="col-lg-2 control-label">Links</label> <label for="inputPostAbsPath" class="col-lg-2 control-label"
>Links</label
>
<div class="col-lg-10"> <div class="col-lg-10">
<p class="help-block" <p class="help-block">
><a ng-href="{{Post.selected.url}}"><span <a ng-href="{{Post.selected.url}}"
ng-bind="Post.selected.url"></span></a> ><span ng-bind="Post.selected.url"></span
></a>
</p> </p>
<input <input
required="required" required="required"
ng-model="Post.selected.markdown" ng-model="Post.selected.markdown"
ng-change="Post.onChange()" ng-change="Post.onChange()"
@ -151,8 +181,8 @@
class="form-control" class="form-control"
id="inputPostMarkdown" id="inputPostMarkdown"
placeholder="i.e. [My First Post](/articles/my-first-post.html)" placeholder="i.e. [My First Post](/articles/my-first-post.html)"
> />
<input <input
required="required" required="required"
ng-model="Post.selected.ahref" ng-model="Post.selected.ahref"
ng-change="Post.onChange()" ng-change="Post.onChange()"
@ -160,10 +190,10 @@
class="form-control" class="form-control"
id="inputPostAhref" id="inputPostAhref"
placeholder="i.e. <a href='/articles/my-first-post.html'>My First Post</a>" placeholder="i.e. <a href='/articles/my-first-post.html'>My First Post</a>"
> />
</div> </div>
</div> </div>
<!--div class="form-group"> <!--div class="form-group">
<label for="inputPostAbsPath" class="col-lg-2 control-label">URL</label> <label for="inputPostAbsPath" class="col-lg-2 control-label">URL</label>
<div class="col-lg-10"> <div class="col-lg-10">
@ -179,7 +209,7 @@
> >
</div> </div>
</div--> </div-->
<!-- <!--
<div class="form-group"> <div class="form-group">
<label for="select" class="col-lg-2 control-label">Selects</label> <label for="select" class="col-lg-2 control-label">Selects</label>
@ -229,17 +259,21 @@
<div class="form-group"> <div class="form-group">
<div class="col-lg-10 col-lg-offset-2"> <div class="col-lg-10 col-lg-offset-2">
<!--button class="btn btn-default">Save Draft</button--> <!--button class="btn btn-default">Save Draft</button-->
<button <button type="submit" class="btn btn-primary pull-right">
type="submit" Publish
class="btn btn-primary pull-right" </button>
>Publish</button>
</div> </div>
</div> </div>
</fieldset> </fieldset>
<div id="source-button" class="btn btn-primary btn-xs" style="display: none;">&lt; &gt;</div> <div
id="source-button"
class="btn btn-primary btn-xs"
style="display: none"
>
&lt; &gt;
</div>
</div> </div>
</div> </div>
</div> </div>
</form> </form>
</div> </div>

View File

@ -1,210 +1,269 @@
'use strict'; "use strict";
angular.module('myApp.post', ['ngRoute']) angular
.module("myApp.post", ["ngRoute"])
.config(['$routeProvider', function($routeProvider) { .config([
$routeProvider.when('/post', { "$routeProvider",
templateUrl: 'views/post/post.html', function ($routeProvider) {
controller: 'PostCtrl as Post' $routeProvider.when("/post", {
}); templateUrl: "views/post/post.html",
}]) controller: "PostCtrl as Post",
});
},
])
.controller('PostCtrl' .controller("PostCtrl", [
, ['$scope', '$location', '$timeout', 'Desirae' "$scope",
, function ($scope, $location, $timeout, DesiraeService) { "$location",
var scope = this "$timeout",
, path = window.path "Desirae",
; function ($scope, $location, $timeout, DesiraeService) {
var scope = this,
function init() { path = window.path;
DesiraeService.meta().then(function (desi) { function init() {
/* DesiraeService.meta()
.then(function (desi) {
/*
if (!scope.site.base_url) { if (!scope.site.base_url) {
window.alert("Please go to the site tab and add a url first"); window.alert("Please go to the site tab and add a url first");
return; return;
} }
*/ */
scope.blogdir = desi.blogdir.path.replace(/^\/(Users|home)\/[^\/]+\//, '~/'); scope.blogdir = desi.blogdir.path.replace(
scope.site = desi.site; /^\/(Users|home)\/[^\/]+\//,
scope.env = desi.site; "~/"
newPost(); );
scope.site = desi.site;
scope.env = desi.site;
newPost();
if (/dropbox/.test(scope.site.base_url)) { if (/dropbox/.test(scope.site.base_url)) {
scope.env.explicitIndexes = true; scope.env.explicitIndexes = true;
}
updateDate();
})
.catch(function (e) {
window.alert(
"An Error Occured. Most errors that occur in the init phase are parse errors in the config files or permissions errors on files or directories, but check the error console for details."
);
console.error(e);
throw e;
});
scope.extensions = ["md", "html"];
} }
updateDate(); function newPost() {
}).catch(function (e) { scope.selected = {
window.alert("An Error Occured. Most errors that occur in the init phase are parse errors in the config files or permissions errors on files or directories, but check the error console for details."); format: "md",
console.error(e); permalink: "/article/new.html",
throw e; uuid: window.uuid.v4(),
}); abspath: scope.blogdir,
sourcepath: "",
fileepath: "",
post: {
yml: {
title: "",
permalink: "/article/new.html",
date: DesiraeService.toDesiDate(new Date()), // "YYYY-MM-DD HH:MM pm" // TODO desirae
updated: null,
description: "",
categories: [],
tags: [],
theme: null,
layout: null,
swatch: null,
},
},
};
scope.selected.date = scope.selected.post.yml.date;
scope.selected.post.frontmatter = window.jsyaml
.dump(scope.selected.post.yml)
.trim();
}
scope.extensions = ['md', 'html']; scope.onChange = function () {
} var post = scope.selected.post,
selected = scope.selected;
post.yml.title = post.yml.title || "";
selected.title = post.yml.title;
post.yml.description = post.yml.description || "";
function newPost() { scope.slug = post.yml.title
scope.selected = { .toLowerCase()
format: 'md' .replace(/["']/g, "")
, permalink: "/article/new.html" .replace(/\W/g, "-")
, uuid: window.uuid.v4() .replace(/^-+/g, "")
, abspath: scope.blogdir .replace(/-+$/g, "")
, sourcepath: '' .replace(/--/g, "-");
, fileepath: ''
, post: { if (selected.permalink === post.yml.permalink) {
yml: { selected.permalink = "/articles/" + scope.slug + "/";
title: "" // + '.html' //+ selected.format
, permalink: "/article/new.html"
, date: DesiraeService.toDesiDate(new Date())// "YYYY-MM-DD HH:MM pm" // TODO desirae post.yml.permalink = selected.permalink;
, updated: null
, description: ""
, categories: []
, tags: []
, theme: null
, layout: null
, swatch: null
} }
} /*
};
scope.selected.date = scope.selected.post.yml.date;
scope.selected.post.frontmatter = window.jsyaml.dump(scope.selected.post.yml).trim();
}
scope.onChange = function () {
var post = scope.selected.post
, selected = scope.selected
;
post.yml.title = post.yml.title || '';
selected.title = post.yml.title;
post.yml.description = post.yml.description || '';
scope.slug = post.yml.title.toLowerCase()
.replace(/["']/g, '')
.replace(/\W/g, '-')
.replace(/^-+/g, '')
.replace(/-+$/g, '')
.replace(/--/g, '-')
;
if (selected.permalink === post.yml.permalink) {
selected.permalink = '/articles/' + scope.slug + '/';
// + '.html' //+ selected.format
post.yml.permalink = selected.permalink;
}
/*
if (path.extname(post.yml.permalink) !== '.' + selected.format) { if (path.extname(post.yml.permalink) !== '.' + selected.format) {
post.yml.permalink = post.yml.permalink.replace(/\.\w+$/, '.' + selected.format); post.yml.permalink = post.yml.permalink.replace(/\.\w+$/, '.' + selected.format);
} }
*/ */
post.frontmatter = window.jsyaml.dump(post.yml).trim(); post.frontmatter = window.jsyaml.dump(post.yml).trim();
// TODO use some sort of filepath pattern in config.yml // TODO use some sort of filepath pattern in config.yml
selected.path = path.join((scope.env.compiled_path || 'compiled'), post.yml.permalink); selected.path = path.join(
if (!/\.html?$/.test(selected.path)) { scope.env.compiled_path || "compiled",
selected.path = path.join(selected.path, 'index.html'); post.yml.permalink
} );
if (!/\.html?$/.test(selected.path)) {
selected.path = path.join(selected.path, "index.html");
}
selected.url = path.join(scope.site.base_url + path.join(scope.site.base_path, post.yml.permalink)); selected.url = path.join(
if (scope.env.explicitIndexes && /\/$/.test(selected.url)) { scope.site.base_url +
selected.url += 'index.html'; path.join(scope.site.base_path, post.yml.permalink)
} );
selected.markdown = '[' + selected.title + '](' + selected.url + ')'; if (scope.env.explicitIndexes && /\/$/.test(selected.url)) {
selected.ahref = '<a href="' + selected.url + '">' + selected.title + '</a>'; selected.url += "index.html";
selected.abspath = path.join(scope.blogdir, selected.path); }
selected.filepath = path.join((selected.collection || 'posts'), scope.slug + '.' + selected.format); selected.markdown = "[" + selected.title + "](" + selected.url + ")";
selected.sourcepath = path.join(scope.blogdir, (selected.collection || 'posts'), scope.slug + '.' + selected.format); selected.ahref =
}; '<a href="' + selected.url + '">' + selected.title + "</a>";
scope.onFrontmatterChange = function () { selected.abspath = path.join(scope.blogdir, selected.path);
var data selected.filepath = path.join(
, post selected.collection || "posts",
; scope.slug + "." + selected.format
);
selected.sourcepath = path.join(
scope.blogdir,
selected.collection || "posts",
scope.slug + "." + selected.format
);
};
scope.onFrontmatterChange = function () {
var data, post;
try { try {
if (!scope.selected.post.frontmatter || !scope.selected.post.frontmatter.trim()) { if (
throw new Error('deleted frontmatter'); !scope.selected.post.frontmatter ||
} !scope.selected.post.frontmatter.trim()
data = window.jsyaml.load(scope.selected.post.frontmatter); ) {
//scope.selected.format = data.permalink.replace(/.*\.(\w+$)/, '$1'); throw new Error("deleted frontmatter");
if (!data.permalink) { }
data = scope.selected.permalink; data = window.jsyaml.load(scope.selected.post.frontmatter);
} //scope.selected.format = data.permalink.replace(/.*\.(\w+$)/, '$1');
scope.selected.post.yml = data; if (!data.permalink) {
data = scope.selected.permalink;
}
scope.selected.post.yml = data;
post = scope.selected.post; post = scope.selected.post;
scope.selected.path = path.join((scope.env.compiled_path || 'compiled'), post.yml.permalink); scope.selected.path = path.join(
if (!/\.html?$/.test(path.basename(post.yml.permalink))) { scope.env.compiled_path || "compiled",
scope.selected.path = path.join(scope.selected.path.replace(/\.w+$/, ''), 'index.html'); post.yml.permalink
);
if (!/\.html?$/.test(path.basename(post.yml.permalink))) {
scope.selected.path = path.join(
scope.selected.path.replace(/\.w+$/, ""),
"index.html"
);
}
scope.selected.url = path.join(
scope.site.base_url +
path.join(scope.site.base_path, post.yml.permalink)
);
if (scope.env.explicitIndexes && /\/$/.test(scope.selected.url)) {
scope.selected.url += "index.html";
}
scope.selected.abspath = path.join(
scope.blogdir,
scope.selected.path
);
scope.selected.sourcepath = path.join(
scope.blogdir,
scope.selected.collection || "posts",
scope.slug + "." + scope.selected.format
);
scope.selected.filepath = path.join(
scope.selected.collection || "posts",
scope.slug + "." + scope.selected.format
);
} 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();
}
};
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 = DesiraeService.toDesiDate(
new Date()
);
}
scope.onChange();
updateDate();
}, 60 * 1000);
} }
scope.selected.url = path.join(scope.site.base_url + path.join(scope.site.base_path, post.yml.permalink)); scope.upsert = function () {
if (scope.env.explicitIndexes && /\/$/.test(scope.selected.url)) { if (-1 === scope.extensions.indexOf(scope.selected.format)) {
scope.selected.url += 'index.html'; window.alert(
} "." +
scope.selected.abspath = path.join(scope.blogdir, scope.selected.path); scope.selected.format +
scope.selected.sourcepath = path.join(scope.blogdir, (scope.selected.collection || 'posts'), scope.slug + '.' + scope.selected.format); " is not a supported extension.\n\nPlease choose from: ." +
scope.selected.filepath = path.join((scope.selected.collection || 'posts'), scope.slug + '.' + scope.selected.format); scope.extensions.join(" .")
} catch(e) { );
console.error(e); return;
console.error('ignoring update that created parse error'); }
scope.selected.post.frontmatter = window.jsyaml.dump(scope.selected.post.yml).trim();
}
};
function updateDate() { scope.selected.post.yml.uuid = scope.selected.uuid;
$timeout.cancel(scope.dtlock); ["updated", "theme", "layout", "swatch"].forEach(function (key) {
scope.dtlock = $timeout(function () { if (!scope.selected.post.yml[key]) {
if (scope.selected && scope.selected.date === scope.selected.post.yml.date) { delete scope.selected.post.yml[key];
scope.selected.date = scope.selected.post.yml.date = DesiraeService.toDesiDate(new Date()); }
} });
scope.onChange(); scope.onChange();
updateDate();
}, 60 * 1000);
}
scope.upsert = function () { var files = [];
if (-1 === scope.extensions.indexOf(scope.selected.format)) { files.push({
window.alert('.' + scope.selected.format + ' is not a supported extension.\n\nPlease choose from: .' + scope.extensions.join(' .')); path: scope.selected.filepath,
return; contents:
} "---\n" +
scope.selected.post.frontmatter.trim() +
"\n" +
"---\n" +
"\n" +
scope.selected.post.body.trim(),
});
scope.selected.post.yml.uuid = scope.selected.uuid; DesiraeService.putFiles(files)
['updated', 'theme', 'layout', 'swatch'].forEach(function (key) { .then(function (results) {
if (!scope.selected.post.yml[key]) { console.log("TODO check for error");
delete scope.selected.post.yml[key]; console.log(files);
} console.log(results);
}); $location.path("/build");
scope.onChange(); })
.catch(function (e) {
$timeout.cancel(scope.dtlock);
console.error(scope.site);
console.error(e);
window.alert("Error Nation! :/");
throw e;
});
};
var files = [] init();
; },
]);
files.push({
path: scope.selected.filepath
, contents:
'---\n'
+ scope.selected.post.frontmatter.trim()
+ '\n'
+ '---\n'
+ '\n'
+ scope.selected.post.body.trim()
});
DesiraeService.putFiles(files).then(function (results) {
console.log('TODO check for error');
console.log(files);
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;
});
};
init();
}]);

View File

@ -2,11 +2,19 @@
<div class="row"> <div class="row">
<div class="page-header"> <div class="page-header">
<h1>Site Configuration</h1> <h1>Site Configuration</h1>
<h3><span ng-bind="Site.blogdir"></span><button class="btn btn-primary pull-right" type="submit" form="formSiteConf">Save &amp; Continue</button></h3> <h3>
<span ng-bind="Site.blogdir"></span
><button
class="btn btn-primary pull-right"
type="submit"
form="formSiteConf"
>
Save &amp; Continue
</button>
</h3>
</div> </div>
</div> </div>
<form id="formSiteConf" class="form-horizontal" ng-submit="Site.upsert()"> <form id="formSiteConf" class="form-horizontal" ng-submit="Site.upsert()">
<div class="row"> <div class="row">
<div class="col-lg-12"> <div class="col-lg-12">
@ -15,42 +23,59 @@
<legend>General</legend> <legend>General</legend>
<div class="form-group"> <div class="form-group">
<label for="inputBlogTitle" class="col-lg-3 control-label">Title</label> <label for="inputBlogTitle" class="col-lg-3 control-label"
>Title</label
>
<div class="col-lg-9"> <div class="col-lg-9">
<input <input
ng-model="Site.site.title" ng-model="Site.site.title"
required="required" required="required"
type="text" class="form-control" id="inputBlogTitle" placeholder="My Awesome Blog"> type="text"
class="form-control"
id="inputBlogTitle"
placeholder="My Awesome Blog"
/>
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="inputBlogTagline" class="col-lg-3 control-label">Tagline</label> <label for="inputBlogTagline" class="col-lg-3 control-label"
>Tagline</label
>
<div class="col-lg-9"> <div class="col-lg-9">
<input <input
ng-model="Site.site.tagline" ng-model="Site.site.tagline"
type="text" class="form-control" id="inputBlogTagline" type="text"
placeholder="i.e. I have not failed, I've just found 10,000 ways that do not work."> class="form-control"
id="inputBlogTagline"
placeholder="i.e. I have not failed, I've just found 10,000 ways that do not work."
/>
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-lg-12"> <div class="col-lg-12">
<div class="form-group"> <div class="form-group">
<label for="inputSiteDesc" class="col-lg-3 control-label">Description <label for="inputSiteDesc" class="col-lg-3 control-label"
<small>(<span ng-bind="Site.site.description.length || 0"></span>/140)</small></label> >Description
<small
>(<span ng-bind="Site.site.description.length || 0"></span
>/140)</small
></label
>
<div class="col-lg-9"> <div class="col-lg-9">
<textarea <textarea
ng-model="Site.site.description" ng-model="Site.site.description"
required="required" required="required"
class="form-control" id="inputSiteDesc" placeholder="i.e. For tips and tricks for try-hard ethical master cleanses, 3 wolf moons on Tumblr, disruptive lo-fi, preserving narwhals and eating kale chips, etc. YOLO."></textarea> class="form-control"
id="inputSiteDesc"
placeholder="i.e. For tips and tricks for try-hard ethical master cleanses, 3 wolf moons on Tumblr, disruptive lo-fi, preserving narwhals and eating kale chips, etc. YOLO."
></textarea>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<!-- TODO --> <!-- TODO -->
<!-- <!--
<div class="form-group"> <div class="form-group">
@ -69,7 +94,9 @@
--> -->
<div class="form-group"> <div class="form-group">
<label for="inputProdUrl" class="col-lg-3 control-label">URL</label> <label for="inputProdUrl" class="col-lg-3 control-label"
>URL</label
>
<div class="col-lg-9"> <div class="col-lg-9">
<input <input
ng-model="Site.url" ng-model="Site.url"
@ -78,32 +105,38 @@
placeholder="i.e. https://example.com/myblog" placeholder="i.e. https://example.com/myblog"
type="text" type="text"
class="form-control" class="form-control"
id="inputProdHost"> id="inputProdHost"
<br/> />
<br />
<span class="help-block" <span class="help-block"
><span class="text-muted" ng-bind="Site.base_url"></span ><span class="text-muted" ng-bind="Site.base_url"></span
><strong ><strong
><span ng-bind="Site.base_path"></span ><span ng-bind="Site.base_path"></span
><span ng-bind="Site.dropboxIndex"></span ><span ng-bind="Site.dropboxIndex"></span
></strong> ></strong>
</span>
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="inputProdOutput" class="col-lg-3 control-label">Output Path</label> <label for="inputProdOutput" class="col-lg-3 control-label"
>Output Path</label
>
<div class="col-lg-9"> <div class="col-lg-9">
<input <input
ng-value="Site.blogdir + '/compiled'" ng-value="Site.blogdir + '/compiled'"
type="text" class="form-control" id="inputProdOutput" disabled> type="text"
class="form-control"
id="inputProdOutput"
disabled
/>
</div> </div>
</div> </div>
</fieldset> </fieldset>
</div> </div>
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-lg-12"> <div class="col-lg-12">
<div class="well bs-component"> <div class="well bs-component">
@ -111,47 +144,56 @@
<legend>Development</legend> <legend>Development</legend>
<div class="form-group"> <div class="form-group">
<label for="inputDevHost" class="col-lg-3 control-label">Base URL</label> <label for="inputDevHost" class="col-lg-3 control-label"
>Base URL</label
>
<div class="col-lg-9"> <div class="col-lg-9">
<input <input
value="https://local.dear.desi:65080" value="https://local.dear.desi:65080"
type="url" type="url"
class="form-control" class="form-control"
id="inputDevHost" id="inputDevHost"
disabled> disabled
<br/> />
<br />
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="inputDevBase" class="col-lg-3 control-label">Base Path</label> <label for="inputDevBase" class="col-lg-3 control-label"
>Base Path</label
>
<div class="col-lg-9"> <div class="col-lg-9">
<input <input
value="/compiled_dev" value="/compiled_dev"
placeholder="i.e. /blog in https://example.com/blog" placeholder="i.e. /blog in https://example.com/blog"
type="text" class="form-control" id="inputDevBase" type="text"
disabled> class="form-control"
id="inputDevBase"
disabled
/>
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="inputDevOutput" class="col-lg-3 control-label">Output Path</label> <label for="inputDevOutput" class="col-lg-3 control-label"
>Output Path</label
>
<div class="col-lg-9"> <div class="col-lg-9">
<input <input
ng-value="Site.blogdir + '/compiled_dev'" ng-value="Site.blogdir + '/compiled_dev'"
type="text" type="text"
class="form-control" class="form-control"
id="inputDevOutput" id="inputDevOutput"
disabled> disabled
/>
</div> </div>
</div> </div>
</fieldset> </fieldset>
</div> </div>
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-lg-12"> <div class="col-lg-12">
<div class="well bs-component"> <div class="well bs-component">
@ -159,7 +201,9 @@
<legend>Plugins</legend> <legend>Plugins</legend>
<div class="form-group"> <div class="form-group">
<label for="inputGoogleAnalyticsId" class="col-lg-3 control-label">Google Analytics ID</label> <label for="inputGoogleAnalyticsId" class="col-lg-3 control-label"
>Google Analytics ID</label
>
<div class="col-lg-9"> <div class="col-lg-9">
<input <input
ng-model="Site.site.google_analytics_tracking_id" ng-model="Site.site.google_analytics_tracking_id"
@ -167,30 +211,35 @@
type="text" type="text"
class="form-control" class="form-control"
id="inputGoogleAnalyticsId" id="inputGoogleAnalyticsId"
> />
<br/> <br />
<small>Found in the Admin section of Google Analytics</small> <small>Found in the Admin section of Google Analytics</small>
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="inputDisqusShortname" class="col-lg-3 control-label">Disqus Shortname</label> <label for="inputDisqusShortname" class="col-lg-3 control-label"
>Disqus Shortname</label
>
<div class="col-lg-9"> <div class="col-lg-9">
<input <input
ng-model="Site.site.disqus_shortname" ng-model="Site.site.disqus_shortname"
placeholder="i.e. johndoe-blog" placeholder="i.e. johndoe-blog"
type="text" class="form-control" id="inputDisqusShortname" type="text"
> class="form-control"
<br/> id="inputDisqusShortname"
/>
<br />
<small>Found under Admin &gt; Settings in Disqus</small> <small>Found under Admin &gt; Settings in Disqus</small>
</div> </div>
</div> </div>
</fieldset> </fieldset>
</div> </div>
</div> </div>
</div> </div>
<button class="btn btn-primary pull-right" type="submit">Save &amp; Continue</button> <button class="btn btn-primary pull-right" type="submit">
Save &amp; Continue
</button>
</form> </form>
</div> </div>

View File

@ -1,106 +1,124 @@
'use strict'; "use strict";
angular.module('myApp.site', ['ngRoute']) angular
.module("myApp.site", ["ngRoute"])
.config(['$routeProvider', function($routeProvider) { .config([
$routeProvider.when('/site', { "$routeProvider",
templateUrl: 'views/site/site.html', function ($routeProvider) {
controller: 'SiteCtrl as Site' $routeProvider.when("/site", {
}); templateUrl: "views/site/site.html",
}]) controller: "SiteCtrl as Site",
});
},
])
.controller('SiteCtrl', ['$scope', '$location', 'Desirae', function ($scope, $location, Desirae) { .controller("SiteCtrl", [
var scope = this "$scope",
; "$location",
"Desirae",
function ($scope, $location, Desirae) {
var scope = this;
function init() {
console.log("desi loading");
Desirae.meta()
.then(function (desi) {
scope.blogdir = desi.blogdir.path.replace(
/^\/(Users|home)\/[^\/]+\//,
"~/"
);
scope.site = desi.site;
function init() { var parts = Desirae.splitUrl(
console.log('desi loading'); scope.site.base_url + (scope.site.base_path || "/")
Desirae.meta().then(function (desi) { );
scope.blogdir = desi.blogdir.path.replace(/^\/(Users|home)\/[^\/]+\//, '~/'); if (parts) {
scope.site = desi.site; scope.base_url = scope.site.base_url;
scope.base_path = scope.site.base_path;
scope.url = scope.base_url + scope.site.base_path;
}
var parts = Desirae.splitUrl(scope.site.base_url + (scope.site.base_path || '/')) scope.onChange();
; })
.catch(function (e) {
if (parts) { window.alert(
scope.base_url = scope.site.base_url; "An Error Occured. Most errors that occur in the init phase are parse errors in the config files or permissions errors on files or directories, but check the error console for details."
scope.base_path = scope.site.base_path; );
scope.url = scope.base_url + scope.site.base_path; console.error(e);
throw e;
});
} }
scope.onChange(); scope.onChange = function () {
}).catch(function (e) { console.log("new url [0]", scope.url);
window.alert("An Error Occured. Most errors that occur in the init phase are parse errors in the config files or permissions errors on files or directories, but check the error console for details."); var parts = Desirae.splitUrl(scope.url),
console.error(e); url;
throw e;
});
}
scope.onChange = function () { if (!parts) {
console.log('new url [0]', scope.url); scope.base_url = "";
var parts = Desirae.splitUrl(scope.url) scope.base_path = "";
, url return;
; }
if (!parts) { scope.base_url = parts.baseUrl;
scope.base_url = ''; scope.base_path = parts.basePath;
scope.base_path = '';
return;
}
scope.base_url = parts.baseUrl; scope.dropboxIndex = "";
scope.base_path = parts.basePath;
scope.dropboxIndex = ''; url = Desirae.gdrive2host(scope.url);
url = Desirae.gdrive2host(scope.url) if (!url && Desirae.dropbox2host(scope.url)) {
; url = Desirae.dropbox2host(scope.url);
scope.dropboxIndex = "/index.html";
}
if (!url && Desirae.dropbox2host(scope.url)) { console.log("new url [1]", url);
url = Desirae.dropbox2host(scope.url); if (url) {
scope.dropboxIndex = '/index.html'; parts = Desirae.splitUrl(url);
} scope.base_url = parts.baseUrl;
scope.base_path = parts.basePath;
}
console.log('new url [1]', url); //scope.url = scope.base_url + scope.base_path;
};
if (url) { scope.upsert = function () {
parts = Desirae.splitUrl(url); var files = [];
scope.base_url = parts.baseUrl; if (!scope.base_url || !scope.base_path) {
scope.base_path = parts.basePath; window.alert(
} "URL: " +
scope.url +
"\nSomething about your URL doesn't look right."
);
return;
}
// Just in case of http://blog.com/me/ + /blog vs http://blog.com + /me/blog
// don't change it unless it's truly different.
if (
scope.base_url + scope.base_path !==
scope.site.base_url + scope.site.base_path
) {
scope.site.base_url = scope.base_url;
scope.site.base_path = scope.base_path;
}
files.push({ path: "site.yml", contents: scope.site });
//scope.url = scope.base_url + scope.base_path; console.log(files);
}; Desirae.putFiles(files)
.then(function (results) {
console.log("TODO check for error");
console.log(results);
$location.path("/post");
})
.catch(function (e) {
console.error(scope.site);
console.error(e);
window.alert("Error Nation! :/");
throw e;
});
};
scope.upsert = function () { init();
var files = [] },
; ]);
if (!scope.base_url || !scope.base_path) {
window.alert("URL: " + (scope.url) + "\nSomething about your URL doesn't look right.");
return;
}
// Just in case of http://blog.com/me/ + /blog vs http://blog.com + /me/blog
// don't change it unless it's truly different.
if ((scope.base_url + scope.base_path) !== (scope.site.base_url + scope.site.base_path)) {
scope.site.base_url = scope.base_url;
scope.site.base_path = scope.base_path;
}
files.push({ path: 'site.yml', contents: scope.site });
console.log(files);
Desirae.putFiles(files).then(function (results) {
console.log('TODO check for error');
console.log(results);
$location.path('/post');
}).catch(function (e) {
console.error(scope.site);
console.error(e);
window.alert("Error Nation! :/");
throw e;
});
};
init();
}]);

View File

@ -1,16 +1,13 @@
'use strict'; "use strict";
describe('myApp.view1 module', function() { describe("myApp.view1 module", function () {
beforeEach(module("myApp.view1"));
beforeEach(module('myApp.view1')); describe("view1 controller", function () {
it("should ....", inject(function ($controller) {
describe('view1 controller', function(){
it('should ....', inject(function($controller) {
//spec body //spec body
var view1Ctrl = $controller('View1Ctrl'); var view1Ctrl = $controller("View1Ctrl");
expect(view1Ctrl).toBeDefined(); expect(view1Ctrl).toBeDefined();
})); }));
}); });
}); });