'use strict'; var async = require('async'); var winston = require('winston'); var templates = require('templates.js'); var _ = require('lodash'); var plugins = require('../plugins'); var translator = require('../translator'); var db = require('../database'); var apiController = require('../controllers/api'); var widgets = module.exports; widgets.render = function (uid, options, callback) { if (!options.template) { return callback(new Error('[[error:invalid-data]]')); } async.waterfall([ function (next) { widgets.getWidgetDataForTemplates(['global', options.template], next); }, function (data, next) { var widgetsByLocation = {}; delete data.global.drafts; var locations = _.uniq(Object.keys(data.global).concat(Object.keys(data[options.template]))); var returnData = {}; async.each(locations, function (location, done) { widgetsByLocation[location] = (data.global[location] || []).concat(data[options.template][location] || []); if (!widgetsByLocation[location].length) { return done(null, { location: location, widgets: [] }); } async.map(widgetsByLocation[location], function (widget, next) { if (!widget || !widget.data || (!!widget.data['hide-registered'] && uid !== 0) || (!!widget.data['hide-guests'] && uid === 0) || (!!widget.data['hide-mobile'] && options.req.useragent.isMobile)) { return next(); } renderWidget(widget, uid, options, next); }, function (err, renderedWidgets) { if (err) { return done(err); } returnData[location] = renderedWidgets.filter(Boolean); done(); }); }, function (err) { next(err, returnData); }); }, ], callback); }; function renderWidget(widget, uid, options, callback) { async.waterfall([ function (next) { if (options.res.locals.isAPI) { apiController.loadConfig(options.req, next); } else { next(null, options.res.locals.config); } }, function (config, next) { var templateData = _.assign({ }, options.templateData, { config: config }); plugins.fireHook('filter:widget.render:' + widget.widget, { uid: uid, area: options, templateData: templateData, data: widget.data, req: options.req, res: options.res, }, next); }, function (data, next) { if (!data) { return callback(); } var html = data; if (typeof html !== 'string') { html = data.html; } else { winston.warn('[widgets.render] passing a string is deprecated!, filter:widget.render:' + widget.widget + '. Please set hookData.html in your plugin.'); } if (widget.data.container && widget.data.container.match('{body}')) { translator.translate(widget.data.title, function (title) { html = templates.parse(widget.data.container, { title: title, body: html, }); next(null, { html: html }); }); } else { next(null, { html: html }); } }, ], callback); } widgets.getWidgetDataForTemplates = function (templates, callback) { var keys = templates.map(function (tpl) { return 'widgets:' + tpl; }); async.waterfall([ function (next) { db.getObjects(keys, next); }, function (data, next) { var returnData = {}; templates.forEach(function (template, index) { returnData[template] = returnData[template] || {}; var templateWidgetData = data[index] || {}; var locations = Object.keys(templateWidgetData); locations.forEach(function (location) { if (templateWidgetData && templateWidgetData[location]) { try { returnData[template][location] = JSON.parse(templateWidgetData[location]); } catch (err) { winston.error('can not parse widget data. template: ' + template + ' location: ' + location); returnData[template][location] = []; } } else { returnData[template][location] = []; } }); }); next(null, returnData); }, ], callback); }; widgets.getArea = function (template, location, callback) { async.waterfall([ function (next) { db.getObjectField('widgets:' + template, location, next); }, function (result, next) { if (!result) { return callback(null, []); } try { result = JSON.parse(result); } catch (err) { return callback(err); } next(null, result); }, ], callback); }; widgets.setArea = function (area, callback) { if (!area.location || !area.template) { return callback(new Error('Missing location and template data')); } db.setObjectField('widgets:' + area.template, area.location, JSON.stringify(area.widgets), callback); }; widgets.reset = function (callback) { var defaultAreas = [ { name: 'Draft Zone', template: 'global', location: 'header' }, { name: 'Draft Zone', template: 'global', location: 'footer' }, { name: 'Draft Zone', template: 'global', location: 'sidebar' }, ]; var drafts; async.waterfall([ function (next) { async.parallel({ areas: function (next) { plugins.fireHook('filter:widgets.getAreas', defaultAreas, next); }, drafts: function (next) { widgets.getArea('global', 'drafts', next); }, }, next); }, function (results, next) { drafts = results.drafts || []; async.each(results.areas, function (area, next) { async.waterfall([ function (next) { widgets.getArea(area.template, area.location, next); }, function (areaData, next) { drafts = drafts.concat(areaData); area.widgets = []; widgets.setArea(area, next); }, ], next); }, next); }, function (next) { widgets.setArea({ template: 'global', location: 'drafts', widgets: drafts, }, next); }, ], callback); }; module.exports = widgets;