UNPKG

4.57 kBJavaScriptView Raw
1'use strict';
2
3const _ = require('lodash');
4const fontKeyFormat = new RegExp(/\w+(-\w*)*-font$/);
5const fontProviders = {
6 'Google': {
7 /**
8 * Parser for Google fonts
9 *
10 * @param {Array} fonts - Array of fonts that might look like
11 * Google_Open+Sans
12 * Google_Open+Sans_400
13 * Google_Open+Sans_400_sans
14 * Google_Open+Sans_400,700_sans
15 * Google_Open+Sans_400,700italic
16 * Google_Open+Sans_400,700italic_sans
17 *
18 * @returns {string}
19 */
20 parser: function(fonts) {
21 var collection = [],
22 familyHash = {};
23
24 _.each(fonts, function fontsIterator(font) {
25 var split = font.split('_'),
26 familyKey = split[1], // Eg: Open+Sans
27 weights = split[2]; // Eg: 400,700italic
28
29 if (_.isEmpty(familyKey)) {
30 return;
31 }
32
33 if (_.isUndefined(weights)) {
34 weights = '';
35 }
36
37 if (!_.isArray(familyHash[familyKey])) {
38 familyHash[familyKey] = [];
39 }
40
41 weights = weights.split(',');
42
43 familyHash[familyKey].push(weights);
44 familyHash[familyKey] = _.uniq(_.flatten(familyHash[familyKey]));
45 });
46
47 _.each(familyHash, function fontHashIterator(weights, family) {
48 collection.push(family + ':' + weights.join(','));
49 });
50
51 return collection;
52 },
53
54 buildLink: function(fonts, fontDisplay) {
55 const displayTypes = ['auto', 'block', 'swap', 'fallback', 'optional'];
56 fontDisplay = displayTypes.includes(fontDisplay) ? fontDisplay : 'swap';
57 return `<link href="https://fonts.googleapis.com/css?family=${fonts.join('|')}&display=${fontDisplay}" rel="stylesheet">`;
58 },
59
60 buildFontLoaderConfig: function(fonts) {
61 function replaceSpaces(font) {
62 return font.split('+').join(' ');
63 }
64
65 return {
66 google: {
67 families: _.map(fonts, replaceSpaces),
68 }
69 };
70 },
71 },
72};
73
74/**
75 * Get collection of fonts used in theme settings.
76 *
77 * @param {Object} paper The paper instance
78 * @param {string} format The desired return value. If format == 'providerLists', return an object with provider names for keys
79 * and a list of fonts in the provider format as values, suitable for use with Web Font Loader. If format == 'linkElements',
80 * return a string containing <link> elements to be directly inserted into the page. If format == 'webFontLoaderConfig', return an
81 * object that can be used to configure Web Font Loader.
82 * @param {Object} options an optional object for additional configuration details
83 * @returns {Object.<string, Array>|string}
84 */
85module.exports = function(paper, format, options) {
86 // Collect font strings from theme settings
87 const collectedFonts = {};
88 _.each(paper.themeSettings, function(value, key) {
89 if (!fontKeyFormat.test(key)) {
90 return;
91 }
92
93 const splits = value.split('_');
94 const provider = splits[0];
95
96 if (typeof fontProviders[provider] === 'undefined') {
97 return;
98 }
99
100 if (typeof collectedFonts[provider] === 'undefined') {
101 collectedFonts[provider] = [];
102 }
103
104 collectedFonts[provider].push(value);
105 });
106
107 // Parse font strings based on provider
108 const parsedFonts = _.mapValues(collectedFonts, function(value, key) {
109 return fontProviders[key].parser(value);
110 });
111
112 // Format output based on requested format
113 switch(format) {
114 case 'linkElements':
115 const formattedFonts = _.mapValues(parsedFonts, function(value, key) {
116 return fontProviders[key].buildLink(value, options.fontDisplay);
117 });
118 return new paper.handlebars.SafeString(_.values(formattedFonts).join(''));
119
120 case 'webFontLoaderConfig':
121 // Build configs
122 const configs = _.mapValues(parsedFonts, function(value, key) {
123 return fontProviders[key].buildFontLoaderConfig(value);
124 });
125
126 // Merge them
127 const fontLoaderConfig = {};
128 _.each(configs, function(config) {
129 return Object.assign(fontLoaderConfig, config);
130 });
131 return fontLoaderConfig;
132
133 case 'providerLists':
134 default:
135 return parsedFonts;
136 }
137}