FEATURE: Use Glimmer compiler for widget templates

Widgets can now specify a template which is precompiled using Glimmer's
AST and then converted into our virtual dom code.

Example:

```javascript
createWidget('post-link-arrow', {
  template: hbs`
    {{#if attrs.above}}
      <a class="post-info arrow" title={{i18n "topic.jump_reply_up"}}>
        {{fa-icon "arrow-up"}}
      </a>
    {{else}}
      <a class="post-info arrow" title={{i18n "topic.jump_reply_down"}}>
        {{fa-icon "arrow-down"}}
      </a>
    {{/if}}
  `,

  click() {
    DiscourseURL.routeTo(this.attrs.shareUrl);
  }
});
```
This commit is contained in:
Robin Ward
2017-06-29 16:22:19 -04:00
parent 7f8a90ef63
commit dffb1fc4ee
10 changed files with 403 additions and 77 deletions
@@ -2,21 +2,21 @@ import PostCooked from 'discourse/widgets/post-cooked';
import DecoratorHelper from 'discourse/widgets/decorator-helper';
import { createWidget } from 'discourse/widgets/widget';
import { h } from 'virtual-dom';
import { iconNode } from 'discourse-common/lib/icon-library';
import DiscourseURL from 'discourse/lib/url';
import hbs from 'discourse/widgets/hbs-compiler';
createWidget('post-link-arrow', {
html(attrs) {
if (attrs.above) {
return h('a.post-info.arrow', {
attributes: { title: I18n.t('topic.jump_reply_up') }
}, iconNode('arrow-up'));
} else {
return h('a.post-info.arrow', {
attributes: { title: I18n.t('topic.jump_reply_down') }
}, iconNode('arrow-down'));
}
},
template: hbs`
{{#if attrs.above}}
<a class="post-info arrow" title={{i18n "topic.jump_reply_up"}}>
{{fa-icon "arrow-up"}}
</a>
{{else}}
<a class="post-info arrow" title={{i18n "topic.jump_reply_down"}}>
{{fa-icon "arrow-down"}}
</a>
{{/if}}
`,
click() {
DiscourseURL.routeTo(this.attrs.shareUrl);
@@ -0,0 +1,3 @@
export default function hbs() {
console.log('Templates should be precompiled server side');
}
@@ -1,3 +1,4 @@
import hbs from 'discourse/widgets/hbs-compiler';
import { createWidget } from 'discourse/widgets/widget';
import { h } from 'virtual-dom';
@@ -23,14 +24,17 @@ createWidget('menu-links', {
createWidget('menu-panel', {
tagName: 'div.menu-panel',
template: hbs`
<div class='panel-body'>
<div class='panel-body-contents clearfix'>
{{yield}}
</div>
</div>
`,
buildAttributes(attrs) {
if (attrs.maxWidth) {
return { 'data-max-width': attrs.maxWidth };
}
},
html(attrs) {
return h('div.panel-body', h('div.panel-body-contents.clearfix', attrs.contents()));
}
});
@@ -1,17 +1,18 @@
import { createWidget } from 'discourse/widgets/widget';
import { h } from 'virtual-dom';
import hbs from 'discourse/widgets/hbs-compiler';
export default createWidget('post-placeholder', {
tagName: 'article.placeholder',
html() {
return h('div.row', [
h('div.topic-avatar', h('div.placeholder-avatar')),
h('div.topic-body', [
h('div.placeholder-text'),
h('div.placeholder-text'),
h('div.placeholder-text')
])
]);
}
template: hbs`
<div class='row'>
<div class='topic-avatar'>
<div class='placeholder-avatar'></div>
</div>
<div class='topic-body'>
<div class='placeholder-text'></div>
<div class='placeholder-text'></div>
<div class='placeholder-text'></div>
</div>
</div>
`
});
@@ -2,13 +2,11 @@ import { iconNode } from 'discourse-common/lib/icon-library';
import { createWidget } from 'discourse/widgets/widget';
import { h } from 'virtual-dom';
import { avatarFor } from 'discourse/widgets/post';
import hbs from 'discourse/widgets/hbs-compiler';
createWidget('pm-remove-group-link', {
tagName: 'a.remove-invited',
html() {
return iconNode('times');
},
template: hbs`{{fa-icon "times"}}`,
click() {
bootbox.confirm(I18n.t("private_message_info.remove_allowed_group", {name: this.attrs.name}), (confirmed) => {
@@ -35,10 +33,7 @@ createWidget('pm-map-user-group', {
createWidget('pm-remove-link', {
tagName: 'a.remove-invited',
html() {
return iconNode('times');
},
template: hbs`{{fa-icon "times"}}`,
click() {
bootbox.confirm(I18n.t("private_message_info.remove_allowed_user", {name: this.attrs.username}), (confirmed) => {
@@ -112,6 +112,10 @@ export function createWidget(name, opts) {
opts.html = opts.html || emptyContent;
opts.draw = drawWidget;
if (opts.template) {
opts.html = opts.template;
}
Object.keys(opts).forEach(k => result.prototype[k] = opts[k]);
return result;
}