Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 61 additions & 21 deletions scripts/construct-leaflet-map.js
Original file line number Diff line number Diff line change
Expand Up @@ -200,10 +200,29 @@
return output;
};

/**
* Trim whitespace
* @param {string} a
* @returns string
*/
function trim(a) {
return a.trim ? a.trim() : a.replace(/^\s+|\s+$/gm, '');
}

/**
* Gets string of anchor for Leaflet's consumption
* @param {Record<'href' | 'textContent', string>} atts
*/
function makeStringLink(atts) {
const a = document.createElement('a');
a.href = atts.href;
a.textContent = atts.textContent;
a.target = '_blank';
a.rel = 'noopener noreferrer';

return a.outerHTML;
}

function addAttributionToMap(attribution, map) {
if (!attribution) {
return;
Expand All @@ -218,6 +237,19 @@

for (var i = 0, len = attributions.length; i < len; i++) {
var att = trim(attributions[i]);

// add liquid-style attribution: {WP | link: https://wordpress.com}
att = liquid(att, function (match, obj) {
if (obj.link) {
return makeStringLink({
href: obj.link,
textContent: obj.key,
});
}

return match;
});

attControl.addAttribution(att);
}
}
Expand All @@ -228,8 +260,6 @@
return div.innerText || str;
});

var templateRe = /\{ *(.*?) *\}/g;

/**
* It interpolates variables in curly brackets (regex above)
*
Expand All @@ -243,8 +273,8 @@
return str;
}

return str.replace(templateRe, function (match, key) {
var obj = liquid(key);
// @since 2.21.0 allow for a `default` filter for missing properties
return liquid(str, function (match, obj) {
var value = parseKey(data, obj.key);
if (value == null) {
return obj.default || match;
Expand Down Expand Up @@ -301,32 +331,42 @@
return value;
}

var liquidRe = /{+ *(.*?) *}+/g;

/**
* parses liquid tags from a string
*
* @param {string} str
*/
function liquid(str) {
var tags = str.split(' | ');
var obj = {};

// removes initial variable from array
var key = tags.shift();

for (var i = 0, len = tags.length; i < len; i++) {
var tag = tags[i].split(': ');
var tagName = tag.shift();
var tagValue = tag.join(': ') || true;

obj[tagName] = tagValue;
}
function liquid(str, callback) {
return str.replace(liquidRe, function (match, group) {
/** @type string[] */
var tags = group.split(' | ');
var obj = {};

// removes initial variable from array
var filter = tags.shift();

for (var i = 0, len = tags.length; i < len; i++) {
var tag = tags[i];
var delimiter = tag.indexOf(':');
var tagName = trim(delimiter === -1 ? tag : tag.slice(0, delimiter));
var tagValue =
delimiter === -1 ? true : trim(tag.slice(delimiter + 1));

obj[tagName] = tagValue;
}

// always preserve the original string
obj.key = key;
// always preserve the original string
obj.key = filter;

return obj;
return callback(match, obj);
});
}

// export for tests
this.liquid = liquid;

function waitFor(prop, cb) {
if (typeof L !== 'undefined' && typeof L[prop] !== 'undefined') {
cb();
Expand Down
75 changes: 75 additions & 0 deletions tests/addAttribution.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
require('../scripts/construct-leaflet-map');

const plugin = window.WPLeafletMapPlugin;

// mock leaflet functions (kind of long-winded)
const addAttribution = jest.fn();
window.L = {
control: {
attribution: () => ({
addTo: () => ({
addAttribution,
}),
}),
},
map: jest.fn(),
};

const originalAttribution =
'<a href="http://leafletjs.com">Leaflet</a>; © <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors';

describe('addAttribution', () => {
beforeEach(() => {
jest.clearAllMocks();
});

it('does not call addAttribution if not present in options', () => {
plugin.createMap({});

expect(L.map).toHaveBeenCalledWith(undefined, expect.any(Object));
expect(addAttribution).not.toHaveBeenCalled();
});

it('calls addAttribution with original (backwards-compatible) HTML string', () => {
plugin.createMap({
attribution: originalAttribution,
});

const attributions = originalAttribution.split('; ');

expect(addAttribution).toHaveBeenCalledWith(attributions[0]);
expect(addAttribution).toHaveBeenCalledWith(attributions[1]);
});

it('calls original attribution with markdown string', () => {
const attribution =
'{Leaflet | link: http://leafletjs.com}; © {OpenStreetMap | link: http://www.openstreetmap.org/copyright} contributors';

plugin.createMap({
attribution,
});

const attributions = originalAttribution.split('; ');

expect(addAttribution).toHaveBeenCalledWith(
'<a href="http://leafletjs.com" target="_blank" rel="noopener noreferrer">Leaflet</a>'
);
expect(addAttribution).toHaveBeenCalledWith(
'© <a href="http://www.openstreetmap.org/copyright" target="_blank" rel="noopener noreferrer">OpenStreetMap</a> contributors'
);
});

it('works without a space after the filter', () => {
const attribution = '{Leaflet | link:http://leafletjs.com}';

plugin.createMap({
attribution,
});

const attributions = originalAttribution.split('; ');

expect(addAttribution).toHaveBeenCalledWith(
'<a href="http://leafletjs.com" target="_blank" rel="noopener noreferrer">Leaflet</a>'
);
});
});
89 changes: 89 additions & 0 deletions tests/liquid.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
require('../scripts/construct-leaflet-map');

const plugin = window.WPLeafletMapPlugin;

describe('liquid', () => {
const observer = jest.fn();

beforeEach(() => {
jest.clearAllMocks();
});

it('parses a boolean filter', () => {
const str = '{ test | isBoolean }';

plugin.liquid(str, observer);

expect(observer).toHaveBeenCalledWith(
str,
expect.objectContaining({
key: 'test',
isBoolean: true,
})
);
});

it('also parses when liquid tag is doubled', () => {
const str = '{{ test }}';

plugin.liquid(str, observer);

expect(observer).toHaveBeenCalledWith(
str,
expect.objectContaining({
key: 'test',
})
);
});

it('does not parse when tag is malformed', () => {
const str = '{ test ';

const output = plugin.liquid(str, observer);

expect(observer).not.toHaveBeenCalled();
expect(output).toEqual(str);
});

it('does not parse when bar is missing whitespace', () => {
const str = '{ test|isBoolean }';

const output = plugin.liquid(str, observer);

expect(observer).toHaveBeenCalledWith(
expect.any(String),
expect.not.objectContaining({
isBoolean: true,
})
);
});

it('accepts multiple filters', () => {
const str = '{ test | default: yolo | substr: 0,4 | lowercase }';

plugin.liquid(str, observer);

expect(observer).toHaveBeenCalledWith(
expect.any(String),
expect.objectContaining({
key: 'test',
default: 'yolo',
substr: '0,4',
lowercase: true,
})
);
});

it('does not have key as a filter', () => {
const str = '{ key | key: not key }';

plugin.liquid(str, observer);

expect(observer).toHaveBeenCalledWith(
expect.any(String),
expect.objectContaining({
key: 'key',
})
);
});
});
41 changes: 0 additions & 41 deletions tests/types.d.ts

This file was deleted.