/*jshint -W054 */ ;(function (exports) { 'use strict'; window.YAML = window.YAML || {}; window.YAML.parse = exports.jsyaml.load || require('jsyaml').load; // Chrome, Firefox, and even MSIE11+ all support crypto var crypto = window.crypto || window.msCrypto , algos ; // convenience mappings for common digest algorithms algos = { 'sha1': 'SHA-1' , 'sha256': 'SHA-256' , 'sha512': 'SHA-512' }; // The function to generate a sha1sum is the same as generating any digest // but here's a shortcut function anyway function sha1sum(str) { return hashsum('sha1', str); } // a more general convenience function function hashsum(hash, str) { // you have to convert from string to array buffer var ab // you have to represent the algorithm as an object , algo = { name: algos[hash] } ; if ('string' === typeof str) { ab = str2ab(str); } else { ab = str; } // All crypto digest methods return a promise return crypto.subtle.digest(algo, ab).then(function (digest) { // you have to convert the ArrayBuffer to a DataView and then to a hex String return ab2hex(digest); }).catch(function (e) { // if you specify an unsupported digest algorithm or non-ArrayBuffer, you'll get an error console.error('sha1sum ERROR'); console.error(e); throw e; }); } // convert from arraybuffer to hex function ab2hex(ab) { var dv = new DataView(ab) , i , len , hex = '' , c ; for (i = 0, len = dv.byteLength; i < len; i += 1) { c = dv.getUint8(i).toString(16); if (c.length < 2) { c = '0' + c; } hex += c; } return hex; } // convert from string to arraybuffer function str2ab(stringToEncode, insertBom) { stringToEncode = stringToEncode.replace(/\r\n/g,"\n"); var utftext = [] , n , c ; if (true === insertBom) { utftext[0] = 0xef; utftext[1] = 0xbb; utftext[2] = 0xbf; } for (n = 0; n < stringToEncode.length; n += 1) { c = stringToEncode.charCodeAt(n); if (c < 128) { utftext[utftext.length]= c; } else if((c > 127) && (c < 2048)) { utftext[utftext.length] = (c >> 6) | 192; utftext[utftext.length] = (c & 63) | 128; } else { utftext[utftext.length] = (c >> 12) | 224; utftext[utftext.length] = ((c >> 6) & 63) | 128; utftext[utftext.length] = (c & 63) | 128; } } return new Uint8Array(utftext).buffer; } exports.hashsum = hashsum; exports.sha1sum = sha1sum; }('undefined' !== typeof exports && exports || window)); ;(function (exports) { 'use strict'; var fsapi ; function request() { } request.get = function (url/*, query*/) { // Return a new promise. return new Promise(function(resolve, reject) { // Do the usual XHR stuff var req = new XMLHttpRequest() ; req.onload = function() { // This is called even on 404 etc // so check the status if (200 === req.status) { // Resolve the promise with the response text resolve(req.response); } else { // Otherwise reject with the status text // which will hopefully be a meaningful error reject(Error(req.statusText)); } }; // Handle network errors req.onerror = function() { reject(Error("Network Error")); }; // Make the request req.open('GET', url); req.send(); }); }; request.post = function (url/*, query*/, body) { // Return a new promise. return new Promise(function(resolve, reject) { // Do the usual XHR stuff var req = new XMLHttpRequest() ; req.onload = function() { // This is called even on 404 etc // so check the status if (200 === req.status) { // Resolve the promise with the response text resolve(req.response); } else { // Otherwise reject with the status text // which will hopefully be a meaningful error reject(Error(req.statusText)); } }; // Handle network errors req.onerror = function() { reject(Error("Network Error")); }; req.open('POST', url); req.setRequestHeader("Content-Type", "application/json;charset=UTF-8"); // Make the request if ('string' !== typeof body) { body = JSON.stringify(body); } req.send(body); }); }; exports.fsapi = fsapi = {}; fsapi.getMeta = function (collections, opts) { opts = opts || {}; var extensions = '' , dotfiles = '' , contents = '' , sha1sum = '' ; if (Array.isArray(opts.extensions)) { extensions = '&extensions=' + opts.extensions.join(','); // md,markdown,jade,htm,html } if (opts.dotfiles) { dotfiles = '&dotfiles=true'; } if (opts.contents) { contents = '&contents=true'; } if (false === opts.sha1sum) { sha1sum = '&sha1sum=false'; } return request.post('/api/fs/walk?_method=GET' + dotfiles + extensions + contents + sha1sum, { dirs: collections }).then(function (resp) { console.log(collections); return JSON.parse(resp); }); }; fsapi.getContents = function (filepaths) { return request.post('/api/fs/files?_method=GET', { paths: filepaths }).then(function (resp) { return JSON.parse(resp); }); }; fsapi.getConfig = function () { return request.get('/config.yml').then(function (resp) { return exports.YAML.parse(resp); }); }; fsapi.getConfigs = function (confs) { var opts = { extensions: ['yml', 'yaml', 'json'], dotfiles: false, contents: true, sha1sum: true } ; return fsapi.getMeta(confs, opts).then(function (collections) { var obj = {} ; Object.keys(collections).forEach(function (key) { var files = collections[key] , keyname = key.replace(/\.(json|ya?ml|\/)$/i, '') ; obj[keyname] = obj[keyname] || {}; files.forEach(function (file) { var filename = file.name.replace(/\.(json|ya?ml)$/i, '') , data = {} ; if (/\.(ya?ml)$/i.test(file.name)) { console.log(); try { data = exports.YAML.parse(file.contents) || {}; if ("undefined" === obj[keyname][filename]) { data = {}; } } catch(e) { console.error("Could not parse yaml for " + filename); console.error(file); console.error(e); } } else if (/\.(json)$/i.test(file.name)) { try { data = JSON.parse(file.contents) || {}; } catch(e) { console.error("Could not parse json for " + filename); console.error(file); console.error(e); } } else { console.error("Not sure what to do with this one..."); console.error(file); } obj[keyname][filename] = data; /* if (!obj[keyname][filename]) { obj[keyname][filename] = {}; } Object.keys(data).forEach(function (key) { obj[keyname][filename][key] = data[key]; }); */ }); }); return obj; }); }; fsapi.getAllPartials = function () { return fsapi.getConfigs(['partials', 'partials.yml']).then(function (results) { var partials = {} ; Object.keys(results.partials).forEach(function (key) { var partial = partials[key]; Object.keys(partial).forEach(function (prop) { if (partials[prop]) { console.warn('partial \'' + prop + '\' overwritten by ' + key); } partials[prop] = partial[prop]; }); }); return partials; }); }; fsapi.getBlogdir = function () { return request.get('/api/fs').then(function (resp) { return JSON.parse(resp); }); }; fsapi.getAllConfigFiles = function () { return fsapi.getConfigs(['config.yml', 'site.yml', 'authors']).then(function (results) { var authors = results.authors , config = results.config.config , site = results.site.site ; return { config: config, authors: authors, site: site }; }); }; fsapi.getData = function () { return request.get('/data.yml').then(function (resp) { return exports.YAML.parse(resp); }); }; fsapi.getCache = function () { return request.get('/cache.json').then(function (resp) { return JSON.parse(resp); }).catch(function (/*e*/) { return {}; }).then(function (obj) { return obj; }); }; fsapi.getPartials = function () { return request.get('/partials.yml').then(function (resp) { var partials = exports.YAML.parse(resp) ; return partials; }); }; fsapi.copy = function (files) { var body = { files: files }; body = JSON.stringify(body); // this is more or less instant for a few MiB of posts return request.post('/api/fs/copy', body).then(function (resp) { var response = JSON.parse(resp) ; // not accurate for utf8/unicode, but close enough response.size = body.length; return response; }); }; fsapi.putFiles = function (files) { var body = { files: files } ; files.forEach(function (file) { if (!file.contents || 'string' === typeof file.contents) { return; } if (/\.json$/i.test(file.path)) { file.contents = JSON.stringify(file.contents); } else if (/\.ya?ml$/i.test(file.path)) { file.contents = exports.jsyaml.dump(file.contents); } }); body = JSON.stringify(body); // this is more or less instant for a few MiB of posts return request.post('/api/fs/files', body).then(function (resp) { var response = JSON.parse(resp) ; // not accurate for utf8/unicode, but close enough response.size = body.length; return response; }); }; }('undefined' !== typeof exports && exports || window));