Part One: What and Why?

How it Works

Reddit Enhancement Suite

Reddit Enhancement Suite

Reddit Enhancement Suite

Reddit Enhancement Suite

Reddit Enhancement Suite

The RES Way

How it Works

What If...

Example

Positive Side-Effect

Caveat

Part Two: How?

Use Ember's Object Model

// Use `reopen` to add a new property to `App.User`
App.User.reopen({
  screamName: function() {
    return this.get('name').toUpperCase() + "!";
  }.property('name')
});

var fish = App.User.create({ name: 'Evil Trout' });
console.log(fish.get('screamName'));
// EVIL TROUT!

A Note about ES6 Modules

Initializers

Initializers

Example

export default {
  name: 'augment-user',
  initialize: function(container, app) {
    var User = container.lookupFactory('model:user');

    User.reopen({ ... });
  }
}

Container? WTF was that?

Container Example

// Finds the currently instantiated Topic controller
container.lookup('controller:topic');

// Finds the class used to instantiate a model
container.lookupFactory('model:user');

The Resolver

Why is this cool?

Creating a Custom Resolver

var AwesomeResolver = Ember.DefaultResolver.extend({
  resolveTemplate: function(parsedName) {
    var awesomeName = "awesome/" +
      parsedName.fullNameWithoutType;

    return Ember.TEMPLATES[awesomeName] ||
      this.super(parsedName);
  }
});

// Wire it up
var App = Ember.Application.extend({
  Resolver: AwesomeResolver
});

Spider-Man!

With great power...

Template Downsides

HAQL

var patcher = Ember.TemplatePatcher;

patcher.add("061dd3942f735486fbc91b5c7dfcf7a6",
  function(ast, hash, str) {
    var toInject = "<p>hello world</p>";
    patcher.insertAt(ast, "if if if-else if[2]",
      toInject, {"shift": 1});
  });

HAQL

Another approach: Ember.ContainerView

ContainerView Example

// post.hbs
<h1>{{title}}</h1>
{{view 'post-after-title'}}

// post-after-title.js
export default Em.ContainerView.extend();

To Append to it

container.lookupFactory('view:post-after-title').reopen({
  addMyView: function() {
    this.pushObject(Em.View.create({
      templateName: 'my-template'
    }));
  }.on('didInsertElement')
});

About this approach

Idea: {{plugin-outlet}}

{{plugin-outlet}} Example

// post.hbs
{{plugin-outlet 'post-after-title}}

// templates/connectors/post-after-title/add-byline.hbs
By: {{author}}

{{plugin-outlet}}

{{plugin-outlet}}

Communication between Views

Communication between Views

The Ember Way?

The Ember Way?

The Ember Way?

The Ember Way?

The Ember Way?

A different solution

Ember.Evented

var doughBoy = Ember.Object.create(Ember.Evented);

doughBoy.on('poke', function() {
  console.log('hehe!');
});

doughBoy.trigger('poke');

Dependecy Injection

Application Events

app.register('app-events:main',
             Ember.Object.extend(Ember.Evented),
             { singleton: true });

app.inject('controller', 'appEvents', 'app-events:main');
app.inject('route', 'appEvents', 'app-events:main');
app.inject('view', 'appEvents', 'app-events:main');
app.inject('model', 'appEvents', 'app-events:main');

Application Events

// views/composer.js
this.appEvents.trigger('composerResized');

// views/progress-bar.js
var self = this;
this.appEvents.on('composerResized', function() {
  self.reposition();
});

Application Events Downsides

In Conclusion

Thanks!