Skip to content

Commit

Permalink
Merge pull request #133 from mattolson/preconnect
Browse files Browse the repository at this point in the history
STRF-4605: Add resourceHints helper
  • Loading branch information
mattolson authored May 9, 2018
2 parents ac7251f + 61babb5 commit 357ba6c
Show file tree
Hide file tree
Showing 6 changed files with 258 additions and 79 deletions.
11 changes: 11 additions & 0 deletions helpers/getFontLoaderConfig.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
'use strict';

const getFonts = require('../lib/fonts');

module.exports = function(paper) {
const handlebars = paper.handlebars;

handlebars.registerHelper('getFontLoaderConfig', function () {
return new handlebars.SafeString(JSON.stringify(getFonts(paper, 'webFontLoaderConfig')));
});
};
84 changes: 5 additions & 79 deletions helpers/getFontsCollection.js
Original file line number Diff line number Diff line change
@@ -1,85 +1,11 @@
'use strict';

var _ = require('lodash');
const getFonts = require('../lib/fonts');

function helper(paper) {
var handlebars = paper.handlebars;
module.exports = function(paper) {
const handlebars = paper.handlebars;

handlebars.registerHelper('getFontsCollection', function () {
var fontKeyFormat = new RegExp(/\w+(-\w*)*-font$/),
googleFonts = [],
linkElements = [];

_.each(paper.themeSettings, function (value, key) {
var split;

if (fontKeyFormat.test(key)) {
split = value.split('_');

switch (split[0]) {
case 'Google':
googleFonts.push(value);
break;

default:
break;
}
}
});

linkElements.push(googleParser(googleFonts));

return new handlebars.SafeString(linkElements.join(''));
});
}

/**
* Parser for Google fonts
*
* @param fonts - Array of fonts that might look like
* Google_Open+Sans
* Google_Open+Sans_400
* Google_Open+Sans_400_sans
* Google_Open+Sans_400,700_sans
* Google_Open+Sans_400,700italic
* Google_Open+Sans_400,700italic_sans
*
* @returns {string}
*/

function googleParser(fonts) {
var collection = [],
familyHash = {};

_.each(fonts, function fontsIterator(font) {
var split = font.split('_'),
familyKey = split[1], // Eg: Open+Sans
weights = split[2]; // Eg: 400,700italic

if (_.isEmpty(familyKey)) {
return;
}

if (_.isUndefined(weights)) {
weights = '';
}

if (!_.isArray(familyHash[familyKey])) {
familyHash[familyKey] = [];
}

weights = weights.split(',');

familyHash[familyKey].push(weights);
familyHash[familyKey] = _.uniq(_.flatten(familyHash[familyKey]));
return getFonts(paper, 'linkElements');
});


_.each(familyHash, function fontHashIterator(weights, family) {
collection.push(family + ':' + weights.join(','));
});

return '<link href="//fonts.googleapis.com/css?family=' + collection.join('|') + '" rel="stylesheet">';
}

module.exports = helper;
};
38 changes: 38 additions & 0 deletions helpers/resourceHints.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
'use strict';

const _ = require('lodash');
const getFonts = require('../lib/fonts');

const fontResources = {
'Google': [
'//ajax.googleapis.com',
'//fonts.googleapis.com',
'//fonts.gstatic.com',
],
};

module.exports = function(paper) {
paper.handlebars.registerHelper('resourceHints', function() {
function format(host) {
return `<link rel="dns-prefetch preconnect" href="${host}" crossorigin>`;
}

var hosts = [];

// Add cdn
const cdnUrl = paper.settings['cdn_url'] || '';
if (cdnUrl != '') {
hosts.push(cdnUrl);
}

// Add font providers
const fontProviders = _.keys(getFonts(paper, 'providerLists'));
_.each(fontProviders, function(provider) {
if (typeof fontResources[provider] !== 'undefined') {
hosts = hosts.concat(fontResources[provider]);
}
});

return new paper.handlebars.SafeString(_.map(hosts, format).join(''));
});
}
134 changes: 134 additions & 0 deletions lib/fonts.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
'use strict';

const _ = require('lodash');
const fontKeyFormat = new RegExp(/\w+(-\w*)*-font$/);
const fontProviders = {
'Google': {
/**
* Parser for Google fonts
*
* @param {Array} fonts - Array of fonts that might look like
* Google_Open+Sans
* Google_Open+Sans_400
* Google_Open+Sans_400_sans
* Google_Open+Sans_400,700_sans
* Google_Open+Sans_400,700italic
* Google_Open+Sans_400,700italic_sans
*
* @returns {string}
*/
parser: function(fonts) {
var collection = [],
familyHash = {};

_.each(fonts, function fontsIterator(font) {
var split = font.split('_'),
familyKey = split[1], // Eg: Open+Sans
weights = split[2]; // Eg: 400,700italic

if (_.isEmpty(familyKey)) {
return;
}

if (_.isUndefined(weights)) {
weights = '';
}

if (!_.isArray(familyHash[familyKey])) {
familyHash[familyKey] = [];
}

weights = weights.split(',');

familyHash[familyKey].push(weights);
familyHash[familyKey] = _.uniq(_.flatten(familyHash[familyKey]));
});

_.each(familyHash, function fontHashIterator(weights, family) {
collection.push(family + ':' + weights.join(','));
});

return collection;
},

buildLink: function(fonts) {
return '<link href="//fonts.googleapis.com/css?family=' + fonts.join('|') + '" rel="stylesheet">';
},

buildFontLoaderConfig: function(fonts) {
function replaceSpaces(font) {
return font.split('+').join(' ');
}

return {
google: {
families: _.map(fonts, replaceSpaces),
}
};
},
},
};

/**
* Get collection of fonts used in theme settings.
*
* @param {Object} paper The paper instance
* @param {string} format The desired return value. If format == 'providerLists', return an object with provider names for keys
* and a list of fonts in the provider format as values, suitable for use with Web Font Loader. If format == 'linkElements',
* return a string containing <link> elements to be directly inserted into the page. If format == 'webFontLoaderConfig', return an
* object that can be used to configure Web Font Loader.
* @returns {Object.<string, Array>|string}
*/
module.exports = function(paper, format) {
// Collect font strings from theme settings
const collectedFonts = {};
_.each(paper.themeSettings, function(value, key) {
if (!fontKeyFormat.test(key)) {
return;
}

const splits = value.split('_');
const provider = splits[0];

if (typeof fontProviders[provider] === 'undefined') {
return;
}

if (typeof collectedFonts[provider] === 'undefined') {
collectedFonts[provider] = [];
}

collectedFonts[provider].push(value);
});

// Parse font strings based on provider
const parsedFonts = _.mapValues(collectedFonts, function(value, key) {
return fontProviders[key].parser(value);
});

// Format output based on requested format
switch(format) {
case 'linkElements':
const formattedFonts = _.mapValues(parsedFonts, function(value, key) {
return fontProviders[key].buildLink(value);
});
return new paper.handlebars.SafeString(_.values(formattedFonts).join(''));

case 'webFontLoaderConfig':
// Build configs
const configs = _.mapValues(parsedFonts, function(value, key) {
return fontProviders[key].buildFontLoaderConfig(value);
});

// Merge them
const fontLoaderConfig = {};
_.each(configs, function(config) {
return Object.assign(fontLoaderConfig, config);
});
return fontLoaderConfig;

case 'providerLists':
default:
return parsedFonts;
}
}
37 changes: 37 additions & 0 deletions test/helpers/getFontLoaderConfig.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
var Code = require('code'),
Lab = require('lab'),
Paper = require('../../index'),
lab = exports.lab = Lab.script(),
describe = lab.experiment,
expect = Code.expect,
it = lab.it;

function c(template, themeSettings) {
return new Paper({}, themeSettings).loadTemplatesSync({template: template}).render('template', {});
}

describe('getFontLoaderConfig helper', function () {
it('should return the expected font url', function (done) {
const themeSettings = {
'test1-font': 'Google_Open+Sans',
'test2-font': 'Google_Open+Sans_400italic',
'test3-font': 'Google_Open+Sans_700',
'test4-font': 'Google_Karla_700',
'test5-font': 'Google_Lora_400_sans',
'test6-font': 'Google_Volkron',
'test7-font': 'Google_Droid_400,700',
'test8-font': 'Google_Crimson+Text_400,700_sans',
'random-property': 'not a font'
};

const template = "{{getFontLoaderConfig}}";
const expectedConfig = {
google: {
families: ['Open Sans:,400italic,700', 'Karla:700', 'Lora:400', 'Volkron:', 'Droid:400,700', 'Crimson Text:400,700']
}
};

expect(c(template, themeSettings)).to.be.equal(JSON.stringify(expectedConfig));
done();
});
});
33 changes: 33 additions & 0 deletions test/helpers/resourceHints.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
var Code = require('code'),
Lab = require('lab'),
Paper = require('../../index'),
lab = exports.lab = Lab.script(),
describe = lab.experiment,
expect = Code.expect,
it = lab.it;

function c(template, themeSettings) {
return new Paper({}, themeSettings).loadTemplatesSync({template: template}).render('template', {});
}

describe('resourceHints helper', function () {
it('should return the expected google resources', function (done) {
var themeSettings = {
'test1-font': 'Google_Open+Sans',
'test2-font': 'Google_Open+Sans_400italic',
'test3-font': 'Google_Open+Sans_700',
'test4-font': 'Google_Karla_700',
'test5-font': 'Google_Lora_400_sans',
'test6-font': 'Google_Volkron',
'test7-font': 'Google_Droid_400,700',
'test8-font': 'Google_Crimson+Text_400,700_sans',
'random-property': 'not a font'
};

var template = "{{resourceHints}}";

expect(c(template, themeSettings))
.to.be.equal('<link rel="dns-prefetch preconnect" href="//ajax.googleapis.com" crossorigin><link rel="dns-prefetch preconnect" href="//fonts.googleapis.com" crossorigin><link rel="dns-prefetch preconnect" href="//fonts.gstatic.com" crossorigin>');
done();
});
});

0 comments on commit 357ba6c

Please sign in to comment.