flyd
Version:
The less is more, modular, functional reactive programming library
527 lines (466 loc) • 14.6 kB
JavaScript
(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
var curryN = require('ramda/src/curryN');
;
function isFunction(obj) {
return !!(obj && obj.constructor && obj.call && obj.apply);
}
// Globals
var toUpdate = [];
var inStream;
// Library functions use self callback to accept (null, undefined) update triggers.
function map(f, s) {
return combine(function(s, self) { self(f(s.val)); }, [s]);
}
function on(f, s) {
return combine(function(s) { f(s.val); }, [s]);
}
function boundMap(f) { return map(f, this); }
var scan = curryN(3, function(f, acc, s) {
var ns = combine(function(s, self) {
self(acc = f(acc, s.val));
}, [s]);
if (!ns.hasVal) ns(acc);
return ns;
});
var merge = curryN(2, function(s1, s2) {
var s = immediate(combine(function(s1, s2, self, changed) {
if (changed[0]) {
self(changed[0]());
} else if (s1.hasVal) {
self(s1.val);
} else if (s2.hasVal) {
self(s2.val);
}
}, [s1, s2]));
endsOn(combine(function() {
return true;
}, [s1.end, s2.end]), s);
return s;
});
function ap(s2) {
var s1 = this;
return combine(function(s1, s2, self) { self(s1.val(s2.val)); }, [s1, s2]);
}
function initialDepsNotMet(stream) {
stream.depsMet = stream.deps.every(function(s) {
return s.hasVal;
});
return !stream.depsMet;
}
function updateStream(s) {
if ((s.depsMet !== true && initialDepsNotMet(s)) ||
(s.end !== undefined && s.end.val === true)) return;
if (inStream !== undefined) {
toUpdate.push(s);
return;
}
inStream = s;
if (s.depsChanged) s.fnArgs[s.fnArgs.length - 1] = s.depsChanged;
var returnVal = s.fn.apply(s.fn, s.fnArgs);
if (returnVal !== undefined) {
s(returnVal);
}
inStream = undefined;
if (s.depsChanged !== undefined) s.depsChanged = [];
s.shouldUpdate = false;
if (flushing === false) flushUpdate();
}
var order = [];
var orderNextIdx = -1;
function findDeps(s) {
var i, listeners = s.listeners;
if (s.queued === false) {
s.queued = true;
for (i = 0; i < listeners.length; ++i) {
findDeps(listeners[i]);
}
order[++orderNextIdx] = s;
}
}
function updateDeps(s) {
var i, o, list, listeners = s.listeners;
for (i = 0; i < listeners.length; ++i) {
list = listeners[i];
if (list.end === s) {
endStream(list);
} else {
if (list.depsChanged !== undefined) list.depsChanged.push(s);
list.shouldUpdate = true;
findDeps(list);
}
}
for (; orderNextIdx >= 0; --orderNextIdx) {
o = order[orderNextIdx];
if (o.shouldUpdate === true) updateStream(o);
o.queued = false;
}
}
var flushing = false;
function flushUpdate() {
flushing = true;
while (toUpdate.length > 0) {
var s = toUpdate.shift();
if (s.vals.length > 0) s.val = s.vals.shift();
updateDeps(s);
}
flushing = false;
}
function isStream(stream) {
return isFunction(stream) && 'hasVal' in stream;
}
function streamToString() {
return 'stream(' + this.val + ')';
}
function updateStreamValue(s, n) {
if (n !== undefined && n !== null && isFunction(n.then)) {
n.then(s);
return;
}
s.val = n;
s.hasVal = true;
if (inStream === undefined) {
flushing = true;
updateDeps(s);
if (toUpdate.length > 0) flushUpdate(); else flushing = false;
} else if (inStream === s) {
markListeners(s, s.listeners);
} else {
s.vals.push(n);
toUpdate.push(s);
}
}
function markListeners(s, lists) {
var i, list;
for (i = 0; i < lists.length; ++i) {
list = lists[i];
if (list.end !== s) {
if (list.depsChanged !== undefined) {
list.depsChanged.push(s);
}
list.shouldUpdate = true;
} else {
endStream(list);
}
}
}
function createStream() {
function s(n) {
return arguments.length > 0 ? (updateStreamValue(s, n), s)
: s.val;
}
s.hasVal = false;
s.val = undefined;
s.vals = [];
s.listeners = [];
s.queued = false;
s.end = undefined;
s.map = boundMap;
s.ap = ap;
s.of = stream;
s.toString = streamToString;
return s;
}
function addListeners(deps, s) {
for (var i = 0; i < deps.length; ++i) {
deps[i].listeners.push(s);
}
}
function createDependentStream(deps, fn) {
var s = createStream();
s.fn = fn;
s.deps = deps;
s.depsMet = false;
s.depsChanged = deps.length > 0 ? [] : undefined;
s.shouldUpdate = false;
addListeners(deps, s);
return s;
}
function immediate(s) {
if (s.depsMet === false) {
s.depsMet = true;
updateStream(s);
}
return s;
}
function removeListener(s, listeners) {
var idx = listeners.indexOf(s);
listeners[idx] = listeners[listeners.length - 1];
listeners.length--;
}
function detachDeps(s) {
for (var i = 0; i < s.deps.length; ++i) {
removeListener(s, s.deps[i].listeners);
}
s.deps.length = 0;
}
function endStream(s) {
if (s.deps !== undefined) detachDeps(s);
if (s.end !== undefined) detachDeps(s.end);
}
function endsOn(endS, s) {
detachDeps(s.end);
endS.listeners.push(s.end);
s.end.deps.push(endS);
return s;
}
function trueFn() { return true; }
function stream(initialValue) {
var endStream = createDependentStream([], trueFn);
var s = createStream();
s.end = endStream;
s.fnArgs = [];
endStream.listeners.push(s);
if (arguments.length > 0) s(initialValue);
return s;
}
function combine(fn, streams) {
var i, s, deps, depEndStreams;
var endStream = createDependentStream([], trueFn);
deps = []; depEndStreams = [];
for (i = 0; i < streams.length; ++i) {
if (streams[i] !== undefined) {
deps.push(streams[i]);
if (streams[i].end !== undefined) depEndStreams.push(streams[i].end);
}
}
s = createDependentStream(deps, fn);
s.depsChanged = [];
s.fnArgs = s.deps.concat([s, s.depsChanged]);
s.end = endStream;
endStream.listeners.push(s);
addListeners(depEndStreams, endStream);
endStream.deps = depEndStreams;
updateStream(s);
return s;
}
var transduce = curryN(2, function(xform, source) {
xform = xform(new StreamTransformer());
return combine(function(source, self) {
var res = xform['@@transducer/step'](undefined, source.val);
if (res && res['@@transducer/reduced'] === true) {
self.end(true);
return res['@@transducer/value'];
} else {
return res;
}
}, [source]);
});
function StreamTransformer() { }
StreamTransformer.prototype['@@transducer/init'] = function() { };
StreamTransformer.prototype['@@transducer/result'] = function() { };
StreamTransformer.prototype['@@transducer/step'] = function(s, v) { return v; };
module.exports = {
stream: stream,
combine: curryN(2, combine),
isStream: isStream,
transduce: transduce,
merge: merge,
scan: scan,
endsOn: endsOn,
map: curryN(2, map),
on: curryN(2, on),
curryN: curryN,
immediate: immediate,
};
},{"ramda/src/curryN":4}],2:[function(require,module,exports){
var flyd = require('../../lib');
module.exports = function(f, s) {
return flyd.combine(function(s, own) {
flyd.map(own, f(s()));
}, [s]);
};
},{"../../lib":1}],3:[function(require,module,exports){
var flyd = require('../../lib');
module.exports = function(src, term) {
return flyd.endsOn(flyd.merge(term, src.end), flyd.combine(function(src, self) {
self(src());
}, [src]));
};
},{"../../lib":1}],4:[function(require,module,exports){
var _arity = require('./internal/_arity');
var _curry1 = require('./internal/_curry1');
var _curry2 = require('./internal/_curry2');
var _curryN = require('./internal/_curryN');
/**
* Returns a curried equivalent of the provided function, with the
* specified arity. The curried function has two unusual capabilities.
* First, its arguments needn't be provided one at a time. If `g` is
* `R.curryN(3, f)`, the following are equivalent:
*
* - `g(1)(2)(3)`
* - `g(1)(2, 3)`
* - `g(1, 2)(3)`
* - `g(1, 2, 3)`
*
* Secondly, the special placeholder value `R.__` may be used to specify
* "gaps", allowing partial application of any combination of arguments,
* regardless of their positions. If `g` is as above and `_` is `R.__`,
* the following are equivalent:
*
* - `g(1, 2, 3)`
* - `g(_, 2, 3)(1)`
* - `g(_, _, 3)(1)(2)`
* - `g(_, _, 3)(1, 2)`
* - `g(_, 2)(1)(3)`
* - `g(_, 2)(1, 3)`
* - `g(_, 2)(_, 3)(1)`
*
* @func
* @memberOf R
* @category Function
* @sig Number -> (* -> a) -> (* -> a)
* @param {Number} length The arity for the returned function.
* @param {Function} fn The function to curry.
* @return {Function} A new, curried function.
* @see R.curry
* @example
*
* var addFourNumbers = function() {
* return R.sum([].slice.call(arguments, 0, 4));
* };
*
* var curriedAddFourNumbers = R.curryN(4, addFourNumbers);
* var f = curriedAddFourNumbers(1, 2);
* var g = f(3);
* g(4); //=> 10
*/
module.exports = _curry2(function curryN(length, fn) {
if (length === 1) {
return _curry1(fn);
}
return _arity(length, _curryN(length, [], fn));
});
},{"./internal/_arity":5,"./internal/_curry1":6,"./internal/_curry2":7,"./internal/_curryN":8}],5:[function(require,module,exports){
module.exports = function _arity(n, fn) {
// jshint unused:vars
switch (n) {
case 0: return function() { return fn.apply(this, arguments); };
case 1: return function(a0) { return fn.apply(this, arguments); };
case 2: return function(a0, a1) { return fn.apply(this, arguments); };
case 3: return function(a0, a1, a2) { return fn.apply(this, arguments); };
case 4: return function(a0, a1, a2, a3) { return fn.apply(this, arguments); };
case 5: return function(a0, a1, a2, a3, a4) { return fn.apply(this, arguments); };
case 6: return function(a0, a1, a2, a3, a4, a5) { return fn.apply(this, arguments); };
case 7: return function(a0, a1, a2, a3, a4, a5, a6) { return fn.apply(this, arguments); };
case 8: return function(a0, a1, a2, a3, a4, a5, a6, a7) { return fn.apply(this, arguments); };
case 9: return function(a0, a1, a2, a3, a4, a5, a6, a7, a8) { return fn.apply(this, arguments); };
case 10: return function(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9) { return fn.apply(this, arguments); };
default: throw new Error('First argument to _arity must be a non-negative integer no greater than ten');
}
};
},{}],6:[function(require,module,exports){
/**
* Optimized internal two-arity curry function.
*
* @private
* @category Function
* @param {Function} fn The function to curry.
* @return {Function} The curried function.
*/
module.exports = function _curry1(fn) {
return function f1(a) {
if (arguments.length === 0) {
return f1;
} else if (a != null && a['@@functional/placeholder'] === true) {
return f1;
} else {
return fn.apply(this, arguments);
}
};
};
},{}],7:[function(require,module,exports){
var _curry1 = require('./_curry1');
/**
* Optimized internal two-arity curry function.
*
* @private
* @category Function
* @param {Function} fn The function to curry.
* @return {Function} The curried function.
*/
module.exports = function _curry2(fn) {
return function f2(a, b) {
var n = arguments.length;
if (n === 0) {
return f2;
} else if (n === 1 && a != null && a['@@functional/placeholder'] === true) {
return f2;
} else if (n === 1) {
return _curry1(function(b) { return fn(a, b); });
} else if (n === 2 && a != null && a['@@functional/placeholder'] === true &&
b != null && b['@@functional/placeholder'] === true) {
return f2;
} else if (n === 2 && a != null && a['@@functional/placeholder'] === true) {
return _curry1(function(a) { return fn(a, b); });
} else if (n === 2 && b != null && b['@@functional/placeholder'] === true) {
return _curry1(function(b) { return fn(a, b); });
} else {
return fn(a, b);
}
};
};
},{"./_curry1":6}],8:[function(require,module,exports){
var _arity = require('./_arity');
/**
* Internal curryN function.
*
* @private
* @category Function
* @param {Number} length The arity of the curried function.
* @return {array} An array of arguments received thus far.
* @param {Function} fn The function to curry.
*/
module.exports = function _curryN(length, received, fn) {
return function() {
var combined = [];
var argsIdx = 0;
var left = length;
var combinedIdx = 0;
while (combinedIdx < received.length || argsIdx < arguments.length) {
var result;
if (combinedIdx < received.length &&
(received[combinedIdx] == null ||
received[combinedIdx]['@@functional/placeholder'] !== true ||
argsIdx >= arguments.length)) {
result = received[combinedIdx];
} else {
result = arguments[argsIdx];
argsIdx += 1;
}
combined[combinedIdx] = result;
if (result == null || result['@@functional/placeholder'] !== true) {
left -= 1;
}
combinedIdx += 1;
}
return left <= 0 ? fn.apply(this, combined) : _arity(left, _curryN(length, combined, fn));
};
};
},{"./_arity":5}],9:[function(require,module,exports){
var flyd = require('flyd');
var flatMap = require('flyd/module/flatmap');
var takeUntil = require('flyd/module/takeuntil');
document.addEventListener('DOMContentLoaded', function() {
var dragElm = document.getElementById('drag');
var mousedown = flyd.stream();
var mousemove = flyd.stream();
var mouseup = flyd.stream();
dragElm.addEventListener('mousedown', mousedown);
document.addEventListener('mousemove', mousemove);
document.addEventListener('mouseup', mouseup);
var mousedrag = flatMap(function(md) {
var startX = md.offsetX, startY = md.offsetY;
return takeUntil(flyd.map(function(mm) {
mm.preventDefault();
return {
left: mm.clientX - startX,
top: mm.clientY - startY
};
}, mousemove), mouseup);
}, mousedown);
flyd.on(function(pos) {
dragElm.style.top = pos.top + 'px';
dragElm.style.left = pos.left + 'px';
}, mousedrag);
});
},{"flyd":1,"flyd/module/flatmap":2,"flyd/module/takeuntil":3}]},{},[9]);