From a41769e61cbdbd8614df919babc66d47bcea9cda Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Thu, 16 May 2019 09:41:56 -0400 Subject: [PATCH] feat: update meta tags on ajaxify (#7580), fixes #7544 * feat: wip -- refresh meta tags on ajaxify * feat: wrapped up meta tags update on ajaxify feature * fix: removed commented-out line * fix: removed another commented-out line --- public/src/ajaxify.js | 2 ++ public/src/app.js | 64 ++++++++++++++++++++++++++++++++++++++++ src/middleware/header.js | 5 ++-- src/middleware/render.js | 9 ++++++ 4 files changed, 77 insertions(+), 3 deletions(-) diff --git a/public/src/ajaxify.js b/public/src/ajaxify.js index d8753b9a9f..7e0931511e 100644 --- a/public/src/ajaxify.js +++ b/public/src/ajaxify.js @@ -196,7 +196,9 @@ $(document).ready(function () { $('#content, #footer').removeClass('ajaxifying'); + // Only executed on ajaxify. Otherwise these'd be in ajaxify.end() app.refreshTitle(data.title); + app.updateTags(); }); }); } diff --git a/public/src/app.js b/public/src/app.js index 9ca5678f4f..1772f63e23 100644 --- a/public/src/app.js +++ b/public/src/app.js @@ -864,4 +864,68 @@ app.cacheBuster = null; document.head.appendChild(linkEl); }; + + app.updateTags = function () { + var metaWhitelist = ['title', 'description', /og:.+/, /article:.+/].map(function (val) { + return new RegExp(val); + }); + var linkWhitelist = ['canonical', 'alternate', 'up']; + + // Delete the old meta tags + Array.prototype.slice + .call(document.querySelectorAll('head meta')) + .filter(function (el) { + var name = el.getAttribute('property') || el.getAttribute('name'); + return metaWhitelist.some(function (exp) { + return !!exp.test(name); + }); + }) + .forEach(function (el) { + document.head.removeChild(el); + }); + + // Add new meta tags + ajaxify.data._header.tags.meta + .filter(function (tagObj) { + var name = tagObj.name || tagObj.property; + return metaWhitelist.some(function (exp) { + return !!exp.test(name); + }); + }) + .forEach(function (tagObj) { + var metaEl = document.createElement('meta'); + Object.keys(tagObj).forEach(function (prop) { + metaEl.setAttribute(prop, tagObj[prop]); + }); + document.head.appendChild(metaEl); + }); + + // Delete the old link tags + Array.prototype.slice + .call(document.querySelectorAll('head link')) + .filter(function (el) { + var name = el.getAttribute('rel'); + return linkWhitelist.some(function (item) { + return item === name; + }); + }) + .forEach(function (el) { + document.head.removeChild(el); + }); + + // Add new link tags + ajaxify.data._header.tags.link + .filter(function (tagObj) { + return linkWhitelist.some(function (item) { + return item === tagObj.rel; + }); + }) + .forEach(function (tagObj) { + var linkEl = document.createElement('link'); + Object.keys(tagObj).forEach(function (prop) { + linkEl.setAttribute(prop, tagObj[prop]); + }); + document.head.appendChild(linkEl); + }); + }; }()); diff --git a/src/middleware/header.js b/src/middleware/header.js index 5bdab71f55..b347723ddb 100644 --- a/src/middleware/header.js +++ b/src/middleware/header.js @@ -107,7 +107,6 @@ module.exports = function (middleware) { }); }, navigation: async.apply(navigation.get, req.uid), - tags: async.apply(meta.tags.parse, req, data, res.locals.metaTags, res.locals.linkTags), banned: async.apply(user.bans.isBanned, req.uid), banReason: async.apply(user.bans.getReason, req.uid), @@ -180,8 +179,8 @@ module.exports = function (middleware) { templateValues.browserTitle = results.browserTitle; templateValues.navigation = results.navigation; templateValues.unreadCount = unreadCount; - templateValues.metaTags = results.tags.meta; - templateValues.linkTags = results.tags.link; + templateValues.metaTags = data._header.tags.meta; + templateValues.linkTags = data._header.tags.link; templateValues.isAdmin = results.user.isAdmin; templateValues.isGlobalMod = results.user.isGlobalMod; templateValues.showModMenu = results.user.isAdmin || results.user.isGlobalMod || results.user.isMod; diff --git a/src/middleware/render.js b/src/middleware/render.js index 56ee550504..c33d6a8eac 100644 --- a/src/middleware/render.js +++ b/src/middleware/render.js @@ -6,6 +6,7 @@ var validator = require('validator'); var winston = require('winston'); var plugins = require('../plugins'); +var meta = require('../meta'); var translator = require('../translator'); var widgets = require('../widgets'); var utils = require('../utils'); @@ -49,6 +50,14 @@ module.exports = function (middleware) { templateToRender = data.templateData.templateToRender || template; plugins.fireHook('filter:middleware.render', { req: req, res: res, templateData: data.templateData }, next); }, + function parseTags(data, next) { + meta.tags.parse(req, data, res.locals.metaTags, res.locals.linkTags, function (err, tags) { + options._header = { + tags: tags, + }; + next(err, data); + }); + }, function (data, next) { options = data.templateData;