diff --git a/package.json b/package.json index def5528d63..5ba13271b9 100644 --- a/package.json +++ b/package.json @@ -94,6 +94,7 @@ "underscore.deep": "^0.5.1", "validator": "^6.1.0", "winston": "^2.1.0", + "xml": "^1.0.1", "xregexp": "~3.1.0" }, "devDependencies": { diff --git a/src/controllers/index.js b/src/controllers/index.js index 49c1c4c2c2..a3b9361651 100644 --- a/src/controllers/index.js +++ b/src/controllers/index.js @@ -30,6 +30,7 @@ Controllers.admin = require('./admin'); Controllers.globalMods = require('./globalmods'); Controllers.mods = require('./mods'); Controllers.sitemap = require('./sitemap'); +Controllers.osd = require('./osd'); Controllers['404'] = require('./404'); Controllers.errors = require('./errors'); diff --git a/src/controllers/osd.js b/src/controllers/osd.js new file mode 100644 index 0000000000..c83f7f142c --- /dev/null +++ b/src/controllers/osd.js @@ -0,0 +1,32 @@ +'use strict'; + +var xml = require('xml'); +var nconf = require('nconf'); + +var plugins = require('../plugins'); +var meta = require('../meta'); + +module.exports.handle = function (req, res, next) { + if (plugins.hasListeners('filter:search.query')) { + res.type('application/xml').send(generateXML()); + } else { + next(); + } +}; + +function generateXML() { + return xml([{ + OpenSearchDescription: [ + { _attr: { xmlns: 'http://a9.com/-/spec/opensearch/1.1/' } }, + { ShortName: String(meta.config.title || meta.config.browserTitle || 'NodeBB') }, + { Description: String(meta.config.description || '') }, + { Url: { + _attr: { + type: 'text/html', + method: 'get', + template: nconf.get('url') + '/search?term={searchTerms}&in=titlesposts', + }, + } }, + ], + }], { declaration: true, indent: '\t' }); +} diff --git a/src/meta/tags.js b/src/meta/tags.js index fa88fa30b8..5b1097d427 100644 --- a/src/meta/tags.js +++ b/src/meta/tags.js @@ -61,6 +61,14 @@ module.exports = function (Meta) { href: nconf.get('relative_path') + '/manifest.json', }]; + if (plugins.hasListeners('filter:search.query')) { + defaultLinks.push({ + rel: 'search', + type: 'application/opensearchdescription+xml', + href: nconf.get('relative_path') + '/osd.xml', + }); + } + // Touch icons for mobile-devices if (Meta.config['brand:touchIcon']) { defaultLinks.push({ diff --git a/src/routes/meta.js b/src/routes/meta.js index cfeeac5b9b..de0bb52406 100644 --- a/src/routes/meta.js +++ b/src/routes/meta.js @@ -8,4 +8,5 @@ module.exports = function (app, middleware, controllers) { app.get('/robots.txt', controllers.robots); app.get('/manifest.json', controllers.manifest); app.get('/css/previews/:theme', controllers.admin.themes.get); + app.get('/osd.xml', controllers.osd.handle); };