mirror of
				https://github.com/zulip/zulip.git
				synced 2025-10-31 20:13:46 +00:00 
			
		
		
		
	While we could fix this issue by changing the markdown processor, doing so is not a robust solution, because even a momentary bug in the markdown processor could allow cached messages that do not follow our security policy. This change ensures that even if our markdown processor has bugs that result in rendered content that does not properly follow our policy of using rel="noopener noreferrer" on links, we'll still do something reasonable. Co-authored-by: Tim Abbott <tabbott@zulipchat.com> Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
		
			
				
	
	
		
			98 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			98 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| const util = require("./util");
 | |
| 
 | |
| // Below, we register Zulip-specific extensions to the handlebars API.
 | |
| //
 | |
| // IMPORTANT: When adding a new handlebars helper, update the
 | |
| // knownHelpers array in the webpack config so that webpack knows your
 | |
| // helper is registered at runtime and don't try to require them when
 | |
| // bundling.
 | |
| 
 | |
| // We don't want to wait for DOM ready to register the Handlebars helpers
 | |
| // below. There's no need to, as they do not access the DOM.
 | |
| // Furthermore, waiting for DOM ready would introduce race conditions with
 | |
| // other DOM-ready callbacks that attempt to render templates.
 | |
| 
 | |
| Handlebars.registerHelper('plural', function (condition, one, other) {
 | |
|     return condition === 1 ? one : other;
 | |
| });
 | |
| 
 | |
| Handlebars.registerHelper({
 | |
|     eq: function (a, b) { return a === b; },
 | |
|     and: function (...args) {
 | |
|         args.pop(); // Handlebars options
 | |
|         if (args.length === 0) {
 | |
|             return true;
 | |
|         }
 | |
|         const last = args.pop();
 | |
|         for (const arg of args) {
 | |
|             if (!arg || Handlebars.Utils.isEmpty(arg)) {
 | |
|                 return arg;
 | |
|             }
 | |
|         }
 | |
|         return last;
 | |
|     },
 | |
|     or: function (...args) {
 | |
|         args.pop(); // Handlebars options
 | |
|         if (args.length === 0) {
 | |
|             return false;
 | |
|         }
 | |
|         const last = args.pop();
 | |
|         for (const arg of args) {
 | |
|             if (arg && !Handlebars.Utils.isEmpty(arg)) {
 | |
|                 return arg;
 | |
|             }
 | |
|         }
 | |
|         return last;
 | |
|     },
 | |
|     not: function (a) { return !a || Handlebars.Utils.isEmpty(a); },
 | |
| });
 | |
| 
 | |
| // Note that this i18n caching strategy does not allow us to support
 | |
| // live-updating the UI language without reloading the Zulip browser
 | |
| // window.  That constraint would be very hard to change in any case,
 | |
| // though, because of how Zulip renders some strings using the backend
 | |
| // Jinja2 templating engine, so we don't consider this important.
 | |
| const t_cache = new Map();
 | |
| 
 | |
| Handlebars.registerHelper('t', function (i18n_key) {
 | |
|     // Marks a string for translation.
 | |
|     // Example usage:
 | |
|     //     {{t "some English text"}}
 | |
| 
 | |
|     const cache_result = t_cache.get(i18n_key);
 | |
|     if (cache_result !== undefined) {
 | |
|         return cache_result;
 | |
|     }
 | |
|     const result = i18n.t(i18n_key);
 | |
|     const safe_result = new Handlebars.SafeString(result);
 | |
|     t_cache.set(i18n_key, safe_result);
 | |
|     return safe_result;
 | |
| });
 | |
| 
 | |
| Handlebars.registerHelper('tr', function (context, options) {
 | |
|     // Marks a block for translation.
 | |
|     // Example usage 1:
 | |
|     //     {{#tr context}}
 | |
|     //         <p>some English text</p>
 | |
|     //     {{/tr}}
 | |
|     //
 | |
|     // Example usage 2:
 | |
|     //     {{#tr context}}
 | |
|     //         <p>This __variable__ will get value from context</p>
 | |
|     //     {{/tr}}
 | |
|     //
 | |
|     // Notes:
 | |
|     //     1. `context` is very important. It can be `this` or an
 | |
|     //        object or key of the current context.
 | |
|     //     2. Use `__` instead of `{{` and `}}` to declare expressions
 | |
|     const result = i18n.t(options.fn(context).trim().split("\n").map(s => s.trim()).join(" "), context);
 | |
|     return new Handlebars.SafeString(result);
 | |
| });
 | |
| 
 | |
| Handlebars.registerHelper(
 | |
|     "rendered_markdown",
 | |
|     content => new Handlebars.SafeString(util.clean_user_content_links(content))
 | |
| );
 | |
| 
 | |
| window.templates = exports;
 |