mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-01-03 00:15:11 +03:00
✨ Added support for secondary navigation (#11409)
no issue - Secondary navigation means most nav concepts are supported, e.g. header & footer, or left & right - The UI is added separately, this PR adds supporting concepts: - make sure the default value is an empty array - add support in the API (v3 only) - add handling in the navigation helper
This commit is contained in:
parent
60c44d360b
commit
419e12d90a
@ -16,7 +16,11 @@ module.exports = function navigation(options) {
|
||||
options.hash = options.hash || {};
|
||||
options.data = options.data || {};
|
||||
|
||||
var navigationData = options.data.site.navigation,
|
||||
const key = options.hash.type && options.hash.type === 'secondary' ? 'secondary_navigation' : 'navigation';
|
||||
options.hash.isSecondary = options.hash.type && options.hash.type === 'secondary';
|
||||
delete options.hash.type;
|
||||
|
||||
var navigationData = options.data.site[key],
|
||||
currentUrl = options.data.root.relativeUrl,
|
||||
self = this,
|
||||
output;
|
||||
|
@ -2,7 +2,7 @@ const _ = require('lodash');
|
||||
const utils = require('../../index');
|
||||
const mapper = require('./utils/mapper');
|
||||
const _private = {};
|
||||
const deprecatedSettings = ['force_i18n', 'permalinks'];
|
||||
const deprecatedSettings = ['force_i18n', 'permalinks', 'secondary_nav'];
|
||||
|
||||
/**
|
||||
* ### Settings Filter
|
||||
|
@ -94,6 +94,9 @@
|
||||
"navigation": {
|
||||
"defaultValue": "[{\"label\":\"Home\", \"url\":\"/\"},{\"label\":\"Tag\", \"url\":\"/tag/getting-started/\"}, {\"label\":\"Author\", \"url\":\"/author/ghost/\"},{\"label\":\"Help\", \"url\":\"https://ghost.org/docs/\"}]"
|
||||
},
|
||||
"secondary_navigation": {
|
||||
"defaultValue": "[]"
|
||||
},
|
||||
"slack": {
|
||||
"defaultValue": "[{\"url\":\"\", \"username\":\"Ghost\"}]"
|
||||
},
|
||||
|
@ -20,6 +20,7 @@ module.exports = {
|
||||
ghost_head: 'ghost_head',
|
||||
ghost_foot: 'ghost_foot',
|
||||
navigation: 'navigation',
|
||||
secondary_navigation: 'secondary_navigation',
|
||||
meta_title: 'meta_title',
|
||||
meta_description: 'meta_description',
|
||||
og_image: 'og_image',
|
||||
|
@ -47,7 +47,7 @@ describe('Settings Content API', function () {
|
||||
});
|
||||
publicProperties.push('codeinjection_head', 'codeinjection_foot');
|
||||
settings.should.have.properties(publicProperties);
|
||||
Object.keys(settings).length.should.equal(21);
|
||||
Object.keys(settings).length.should.equal(22);
|
||||
|
||||
// Verify that we are returning the defaults for each value
|
||||
_.forEach(settings, (value, key) => {
|
||||
@ -76,7 +76,7 @@ describe('Settings Content API', function () {
|
||||
// Convert empty strings to null
|
||||
defaultValue = defaultValue || null;
|
||||
|
||||
if (defaultKey === 'navigation') {
|
||||
if (defaultKey === 'navigation' || defaultKey === 'secondary_navigation') {
|
||||
defaultValue = JSON.parse(defaultValue);
|
||||
}
|
||||
|
||||
|
@ -31,7 +31,8 @@ describe('{{navigation}} helper', function () {
|
||||
optionsData = {
|
||||
data: {
|
||||
site: {
|
||||
navigation: []
|
||||
navigation: [],
|
||||
secondary_navigation: []
|
||||
},
|
||||
root: {
|
||||
relativeUrl: ''
|
||||
@ -177,6 +178,41 @@ describe('{{navigation}} helper', function () {
|
||||
should.exist(rendered);
|
||||
rendered.string.should.not.containEql('foo=space%2520bar');
|
||||
});
|
||||
|
||||
describe('type="secondary"', function () {
|
||||
it('can render one item', function () {
|
||||
var singleItem = {label: 'Foo', url: '/foo'},
|
||||
testUrl = 'href="' + configUtils.config.get('url') + '/foo"',
|
||||
rendered;
|
||||
|
||||
optionsData.data.site.secondary_navigation = [singleItem];
|
||||
optionsData.hash = {type: 'secondary'};
|
||||
rendered = runHelper(optionsData);
|
||||
|
||||
should.exist(rendered);
|
||||
rendered.string.should.containEql('li');
|
||||
rendered.string.should.containEql('nav-foo');
|
||||
rendered.string.should.containEql(testUrl);
|
||||
});
|
||||
|
||||
it('can render multiple items', function () {
|
||||
var firstItem = {label: 'Foo', url: '/foo'},
|
||||
secondItem = {label: 'Bar Baz Qux', url: '/qux'},
|
||||
testUrl = 'href="' + configUtils.config.get('url') + '/foo"',
|
||||
testUrl2 = 'href="' + configUtils.config.get('url') + '/qux"',
|
||||
rendered;
|
||||
|
||||
optionsData.data.site.secondary_navigation = [firstItem, secondItem];
|
||||
optionsData.hash = {type: 'secondary'};
|
||||
rendered = runHelper(optionsData);
|
||||
|
||||
should.exist(rendered);
|
||||
rendered.string.should.containEql('nav-foo');
|
||||
rendered.string.should.containEql('nav-bar-baz-qux');
|
||||
rendered.string.should.containEql(testUrl);
|
||||
rendered.string.should.containEql(testUrl2);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('{{navigation}} helper with custom template', function () {
|
||||
@ -196,7 +232,8 @@ describe('{{navigation}} helper with custom template', function () {
|
||||
optionsData = {
|
||||
data: {
|
||||
site: {
|
||||
navigation: [{label: 'Foo', url: '/foo'}]
|
||||
navigation: [{label: 'Foo', url: '/foo'}],
|
||||
secondary_navigation: [{label: 'Fighters', url: '/foo'}]
|
||||
},
|
||||
root: {
|
||||
relativeUrl: ''
|
||||
@ -217,6 +254,7 @@ describe('{{navigation}} helper with custom template', function () {
|
||||
should.exist(rendered);
|
||||
rendered.string.should.containEql('Chaos is a ladder');
|
||||
rendered.string.should.not.containEql('isHeader is set');
|
||||
rendered.string.should.not.containEql('Jeremy Bearimy baby!');
|
||||
rendered.string.should.containEql(testUrl);
|
||||
rendered.string.should.containEql('Foo');
|
||||
});
|
||||
@ -233,7 +271,25 @@ describe('{{navigation}} helper with custom template', function () {
|
||||
should.exist(rendered);
|
||||
rendered.string.should.not.containEql('Chaos is a ladder');
|
||||
rendered.string.should.containEql('isHeader is set');
|
||||
rendered.string.should.not.containEql('Jeremy Bearimy baby!');
|
||||
rendered.string.should.containEql(testUrl);
|
||||
rendered.string.should.containEql('Foo');
|
||||
});
|
||||
|
||||
it('sets isSecondary for type=secondary', function () {
|
||||
var testUrl = 'href="' + configUtils.config.get('url') + '/foo"',
|
||||
rendered;
|
||||
|
||||
// Simulate {{navigation type="secondary"}}
|
||||
optionsData.hash = {type: 'secondary'};
|
||||
|
||||
rendered = runHelper(optionsData);
|
||||
|
||||
should.exist(rendered);
|
||||
rendered.string.should.not.containEql('Chaos is a ladder');
|
||||
rendered.string.should.not.containEql('isHeader is set');
|
||||
rendered.string.should.containEql('Jeremy Bearimy baby!');
|
||||
rendered.string.should.containEql(testUrl);
|
||||
rendered.string.should.containEql('Fighters');
|
||||
});
|
||||
});
|
||||
|
@ -2,6 +2,8 @@
|
||||
|
||||
{{#if isHeader}}isHeader is set{{/if}}
|
||||
|
||||
{{#if isSecondary}}Jeremy Bearimy baby!{{/if}}
|
||||
|
||||
{{#foreach navigation}}
|
||||
<a href="{{url absolute="true"}}">{{label}}</a>
|
||||
{{/foreach}}
|
||||
|
@ -113,7 +113,8 @@ describe('Unit: models/settings', function () {
|
||||
|
||||
return models.Settings.populateDefaults()
|
||||
.then(() => {
|
||||
eventSpy.callCount.should.equal(84);
|
||||
// 2 events per item - settings.added and settings.[name].added
|
||||
eventSpy.callCount.should.equal(86);
|
||||
const eventsEmitted = eventSpy.args.map(args => args[0]);
|
||||
const checkEventEmitted = event => should.ok(eventsEmitted.includes(event), `${event} event should be emitted`);
|
||||
|
||||
@ -135,7 +136,8 @@ describe('Unit: models/settings', function () {
|
||||
|
||||
return models.Settings.populateDefaults()
|
||||
.then(() => {
|
||||
eventSpy.callCount.should.equal(82);
|
||||
// 2 events per item - settings.added and settings.[name].added
|
||||
eventSpy.callCount.should.equal(84);
|
||||
|
||||
eventSpy.args[13][0].should.equal('settings.logo.added');
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user