Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- @ = require(['mho:std', 'mho:app']);
- // channel.sjs
- ;(function (exports) {
- exports.pending_limit = 1024
- exports.closed = {}
- function wake(array, value) {
- var f = array.shift()
- return f(value)
- }
- function sleep(chan_this, value) {
- if (chan_this.length < exports.pending_limit) {
- // TODO why doesn't this hold work ?
- // hold(0)
- waitfor (var result) {
- function done(x) {
- // TODO is this a good spot for this ?
- // TODO is there a better way than using hold(0) ?
- hold(0)
- resume(x)
- return value
- }
- chan_this.push(done)
- } retract {
- var index = chan_this.indexOf(done)
- console.log("RETRACTED", index)
- @assert.isNot(index, -1) // TODO test if this is ever possible
- if (index !== -1) {
- chan_this.splice(index, 1)
- }
- }
- return result
- } else {
- throw new Error("cannot have more than #{exports.pending_limit} pending operations on a channel")
- }
- }
- // The behavior is the same as Clojure's core.async channels (http://clojure.github.io/core.async/)
- exports.Channel = function () {
- // TODO what about pending receiver/sender when retracted ?
- var o = @Stream(function (emit) {
- while (true) {
- // TODO I would like to use `exports.take(this)`, but I can't
- var v = exports.take(o)
- if (v === exports.closed) {
- break
- } else {
- emit(v)
- }
- }
- })
- o.closed = false
- o.receiver = []
- o.sender = []
- return o
- }
- exports.take = function (channel) {
- if (channel.sender.length) {
- return wake(channel.sender, null)
- } else if (channel.closed) {
- return exports.closed
- } else {
- return sleep(channel.receiver, null)
- }
- }
- // TODO this used to return something even though it didn't use return! find out why
- exports.put = function (channel, value) {
- if (channel.closed) {
- return false
- } else if (channel.receiver.length) {
- wake(channel.receiver, value)
- return true
- } else {
- sleep(channel.sender, value)
- return true
- }
- }
- exports.close = function (channel) {
- channel.closed = true
- while (channel.receiver.length) {
- wake(channel.receiver, exports.closed)
- }
- }
- exports.isClosed = function (channel) {
- return channel.closed
- }
- })(@)
- // event.sjs
- ;(function (exports) {
- exports.Emitter = function () {
- var o = @Stream(function (emit) {
- // TODO I would like to use `this` rather than `o`
- var c = exports.on(o)
- try {
- c ..@each(emit)
- } finally {
- exports.off(o, c)
- }
- })
- o.listeners = []
- return o
- }
- exports.on = function (emitter) {
- var c = @Channel()
- emitter.listeners.push(c)
- return c
- }
- exports.off = function (emitter, c) {
- emitter.listeners ..@remove(c)
- }
- exports.emit = function (emitter, value) {
- // TODO use each.par instead ?
- emitter.listeners ..@each(function (listener) {
- listener ..@put(value)
- })
- }
- })(@)
- // dom.sjs
- ;(function (exports) {
- exports.events = function (elem, name, info) {
- var o = @Emitter()
- elem.addEventListener(name, function (e) {
- if (info != null) {
- if (info.preventDefault) {
- e.preventDefault()
- }
- }
- o ..@emit(e)
- }, true)
- return o
- }
- })(@)
- function getUpdateFromServer() {
- hold(1000); // simulate server round trip
- return @Div('This is an update from the server');
- }
- @mainContent .. @appendContent(@Btn('default', 'Get status update from server')) {
- |button|
- button .. @events('click') ..@buffer(1, { drop: true }) .. @each {
- ||
- waitfor {
- @mainContent .. @appendContent(getUpdateFromServer());
- }
- or {
- hold(100); // wait a little while before showing feedback
- // actually want to append to status bar here or something, but this is for demo only
- @mainContent .. @appendContent('waiting for server...') { || hold() }
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment