Skip to content

Instantly share code, notes, and snippets.

@kumkanillam
Forked from machty/controllers.application.js
Created December 5, 2016 06:54
Show Gist options
  • Save kumkanillam/d21aa8f8c323233c4dd6b95fdaa98440 to your computer and use it in GitHub Desktop.
Save kumkanillam/d21aa8f8c323233c4dd6b95fdaa98440 to your computer and use it in GitHub Desktop.
New Twiddle
import Ember from 'ember';
import { task, timeout } from 'ember-concurrency';
export default Ember.Controller.extend({
doDestructiveThing: task(function * () {
yield request('confirmation', {
message: "Are you sure?"
});
let color = yield request('colorConfirmation', {
message: "What's your favorite color?",
colors: ["red", "green", "blue", "yellow"]
});
return `You picked ${color}? That's too bad.`;
}).drop(),
});
// TODO: add this as an import
const YIELDABLE = "__ec_yieldable__";
// NOTE: everything below here is stuff library/addon authors
// would write. The whole point of the yieldables API is to
// let addon authors experiment with solutions to common
// UI problems involving async.
let INVOKE = "__invoke_symbol__";
let locations = [
'ember-glimmer/helpers/action',
'ember-routing-htmlbars/keywords/closure-action',
'ember-routing/keywords/closure-action'
];
for (let i = 0; i < locations.length; i++) {
if (locations[i] in Ember.__loader.registry) {
INVOKE = Ember.__loader.require(locations[i])['INVOKE'];
break;
}
}
let Channel;
function request(name, payload) {
return {
[YIELDABLE](taskInstance, index) {
let obj = taskInstance.context;
payload.respond = response => {
taskInstance.proceed(index, "next", response);
};
payload.cancel = () => {
taskInstance.proceed(index, "cancel", null);
};
obj.set(name, payload);
return () => {
obj.set(name, null);
};
},
};
}
Channel = Ember.Object.extend({
init() {
this._super();
this._takes = [];
this._puts = [];
this._refreshState();
this.put = (...args) => this._put(...args);
},
isActive: Ember.computed.or('isPutting', 'isTaking'),
isPutting: false,
isTaking: false,
[YIELDABLE](...args) {
// `yield channel` is the same as
// `yield channel.take()`;
return this.take()[YIELDABLE](...args);
},
take() {
let takeAttempt = {
defer: Ember.RSVP.defer(),
active: true,
[YIELDABLE](taskInstance, resumeIndex) {
console.log("take yieldable");
this.defer.promise.then(value => {
console.log(`resolve ${value}`);
taskInstance.proceed(resumeIndex, "next", value);
});
return () => {
this.active = false;
};
},
};
this._takes.push(takeAttempt);
this._scheduleFlush();
return takeAttempt;
},
_put(value) {
let putAttempt = {
value,
defer: Ember.RSVP.defer(),
active: true,
[YIELDABLE](taskInstance, resumeIndex) {
console.log("put yieldable");
this.defer.promise.then(() => {
taskInstance.proceed(resumeIndex, "next", null);
});
return () => {
this.active = false;
};
},
};
this._puts.push(putAttempt);
this._scheduleFlush();
return putAttempt;
},
_scheduleFlush() {
Ember.run.schedule('actions', this, this._flush);
},
_flush() {
let oldTakes = this._takes;
let puts = this._puts;
let newTakes = [];
for (let i = 0; i < oldTakes.length; ++i) {
let take = oldTakes[i];
if (!take.active) { continue; }
while(puts.length) {
let put = puts.shift();
if (!put.active) { continue; }
console.log("resolving take ", take, " with ", put.value);
take.defer.resolve(put.value);
put.defer.resolve();
continue;
}
newTakes.push(take);
}
this._takes = newTakes;
this._refreshState();
},
_refreshState() {
this.setProperties({
isTaking: this._takes.length > 0,
isPutting: this._putting.length > 0,
});
},
});
function channel() {
return Ember.computed(function() {
return Channel.create();
});
}
<h1>Confirmation modals</h1>
<p>
Inspiration: <a href="https://ember-twiddle.com/34f664b437d9fdc574f3685707825cac">
this Twiddle by James Rosen.
</a>.
</p>
<button onclick={{perform doDestructiveThing}}>
Do Destructive Thing
</button>
{{#with confirmation as |c|}}
<h3>Warning: Destructive Action</h3>
<p>{{c.message}}</p>
<button onclick={{action c.respond "yes"}}>Yes</button>
<button onclick={{action c.cancel}}>No</button>
{{/with }}
{{#with colorConfirmation as |c|}}
<h3>Warning: Destructive Action</h3>
<p>{{c.message}}</p>
{{#each c.colors as |color|}}
<button onclick={{action c.respond color}}>{{color}}</button>
{{/each}}
{{/with}}
<p>{{doDestructiveThing.last.value}}</p>
{
"version": "0.10.1",
"EmberENV": {
"FEATURES": {}
},
"options": {
"use_pods": false,
"enable-testing": false
},
"dependencies": {
"jquery": "https://cdnjs.cloudflare.com/ajax/libs/jquery/1.11.3/jquery.js",
"ember": "2.6.0",
"ember-data": "2.6.1",
"ember-template-compiler": "2.6.0"
},
"addons": {
"ember-concurrency": "pr-100"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment