Gitter migration: Point people to app.gitter.im (rollout pt. 1)
[gitter.git] / public / js / views / behaviors / widgets.js
blob949a47e3c1c181d26a62c0781b8d99fdead4c284
1 /* eslint max-statements: ["error", 41] */
2 'use strict';
4 var _ = require('lodash');
5 var Marionette = require('backbone.marionette');
6 var behaviourLookup = require('./lookup');
7 var unsafeParseHtml = require('../../utils/unsafe-parse-html');
9 var cachedWidgets = {};
11 function register(widgets) {
12   var keys = _.keys(widgets);
13   _.each(keys, function(key) {
14     var value = widgets[key];
15     cachedWidgets[key] = value;
16   });
19 function WidgetManager() {
20   this._widgets = [];
23 WidgetManager.prototype.add = function(widget) {
24   this._widgets.push(widget);
27 WidgetManager.prototype.destroy = function() {
28   _.each(this._widgets, function(item) {
29     item.destroy();
30   });
31   this._widgets = [];
34 // eslint-disable-next-line complexity
35 function render(template, data, view) {
36   if (!template) {
37     var pseudoSelectorString = '';
38     if (view) {
39       pseudoSelectorString += view.childViewContainer;
40       if (view.$el.length > 0) {
41         var viewEl = view.$el[0];
42         if (viewEl.id) {
43           pseudoSelectorString += '#' + viewEl.id;
44         }
45         if (viewEl.classList.length > 0) {
46           pseudoSelectorString += '.' + Array.prototype.join(viewEl.classList, '.');
47         }
48       }
49     }
51     throw new Error(
52       "Cannot render the template since it's false, null or undefined. For context, we tried to render into this element: " +
53         pseudoSelectorString
54     );
55   }
57   var templateFunc;
58   if (typeof template === 'function') {
59     templateFunc = template;
60   } else {
61     templateFunc = Marionette.TemplateCache.get(template);
62   }
64   var generatedText = templateFunc(data);
66   var prerenderedViews = data.prerenderedViews;
68   // No widgets? Just return the text
69   if (!prerenderedViews) return generatedText;
71   var dom = unsafeParseHtml(generatedText);
72   var widgetManager = view.widgetManager;
74   var widgetsRendered = dom.querySelectorAll('.widget');
75   var widgetsRenderedLen = widgetsRendered.length;
77   if (widgetsRenderedLen && !widgetManager) {
78     // Create a region manager if one doesn't already exist
79     widgetManager = new WidgetManager();
80     view.widgetManager = widgetManager;
81   }
83   for (var i = 0; i < widgetsRenderedLen; i++) {
84     var widgetEl = widgetsRendered[i];
85     var id = widgetEl.getAttribute('data-widget-id');
86     if (!id) continue;
87     var attrs = prerenderedViews[id];
88     if (!attrs) continue;
90     widgetEl.removeAttribute('data-widget-id');
92     var Widget = cachedWidgets[attrs.widgetName];
93     var model = attrs.model;
94     model.el = widgetEl; // Existing element
95     model.template = false; // No template (attach)
97     // Attach the widget to the prerendered content
98     var widget = new Widget(model);
99     widget.render();
101     // Add the widget to the widget manager
102     widgetManager.add(widget);
103   }
105   return dom;
108 function getPrerendered(widgetName, model, id) {
109   var Widget = cachedWidgets[widgetName];
110   return Widget.getPrerendered(model, id);
113 var Behavior = Marionette.Behavior.extend({
114   initialize: function() {
115     if (this.view.templateHelpers) throw new Error('Cannot use templateHelpers with Widgets');
116     this.view.templateHelpers = function() {
117       // TODO: add global template helpers
118       return {
119         _view: this,
120         getPrerendered: getPrerendered
121       };
122     };
123   },
124   onDestroy: function() {
125     if (this.view.widgetManager) {
126       this.view.widgetManager.destroy();
127       this.view.widgetManager = null;
128     }
129   }
132 // No simple way to do this...
133 Marionette.Renderer = {
134   render: render
137 behaviourLookup.register('Widgets', Behavior);
139 module.exports = {
140   register: register,
141   Behavior: Behavior