Skip to content

Instantly share code, notes, and snippets.

@chrism
Forked from machty/controllers.application.js
Created December 6, 2016 19:21
Show Gist options
  • Save chrism/d33f8f5f2c9bca300d3f0205de5fa733 to your computer and use it in GitHub Desktop.
Save chrism/d33f8f5f2c9bca300d3f0205de5fa733 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({
showDialogs: task(function * () {
yield alert("Hey, I heard you liked alert()");
yield timeout(50);
let name = yield prompt("May I prompt() you for your name?");
yield timeout(50);
if (yield confirm(`Please confirm() your name is ${name}`)) {
yield alert("Yes!");
} else {
yield alert("No!");
}
}).drop(),
});
function alert(message) {
return request('dialog', { message });
}
function prompt(message) {
return request('dialog', {
message,
showInput: true,
showCancel: true,
});
}
function confirm(message) {
return request('dialog', {
message,
showCancel: true,
value: true
});
}
// 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();
});
}
body {
margin: 12px 16px;
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
font-size: 12pt;
}
.dialog {
position: fixed;
top: 20%;
left: 50%;
}
.dialog input {
position: relative;
width: 100%;
display: block;
margin-top: 10px;
}
.dialog-inner {
width: 400px;
margin-left: -200px;
background: #d4d0c7;
border-right: 1px solid #404040;
border-bottom: 1px solid #404040;
position: relative;
min-height: 100px;
box-sizing: border-box;
padding: 70px 70px 100px 70px;
}
.dialog-inner::after {
position: absolute;
top: 1px;
left: 1px;
right: 0px;
bottom: 0px;
border-right: 1px solid #808080;
border-bottom: 1px solid #808080;
border-left: 1px solid #ffffff;
border-top: 1px solid #ffffff;
content: ' ';
z-index: -1;
}
.dialog-header {
position: absolute;
top: 3px;
left: 3px;
right: 3px;
background: blue;
color: white;
padding: 2px 3px;
}
.dialog-message {
text-align: center;
}
.dialog-buttons {
position: absolute;
bottom: 30px;
left: 0;
right: 0;
text-align: center;
}
.dialog-button {
display: inline-block;
border: 1px solid black;
min-width: 100px;
padding: 8px;
text-align: center;
position: relative;
margin: 0 4px;
}
.dialog-button::after {
content: ' ';
position: absolute;
top: 1px;
left: 1px;
right: 0px;
bottom: 0px;
border-top: 1px solid #ffffff;
border-left: 1px solid #ffffff;
border-right: 1px solid #808080;
border-bottom: 1px solid #808080;
}
<h1>better alert() / prompt() / confirm()</h1>
{{#if dialog}}
<form class="dialog" {{action (action dialog.respond dialog.value) on='submit'}}>
<div class="dialog-inner">
<div class="dialog-header">
Your Dumb Browser
</div>
<div class="dialog-message">
{{dialog.message}}
</div>
{{#if dialog.showInput}}
{{input value=dialog.value autofocus="yes"}}
{{/if}}
<div class="dialog-buttons">
<div class="dialog-button"
onclick={{action dialog.respond dialog.value}}>
OK
</div>
{{#if dialog.showCancel}}
<div class="dialog-button"
onclick={{action dialog.respond null}}>
Cancel
</div>
{{/if}}
</div>
</div>
</form>
{{/if}}
<button onclick={{perform showDialogs}}>
{{if showDialogs.isRunning "Please Wait..." "Show Dialogs" }}
</button>
{
"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