Page MenuHomestyx hydra

RDOM.js
No OneTemporary

/**
* Javelin Reactive functions to work with the DOM.
* @provides javelin-reactor-dom
* @requires javelin-dom
* javelin-dynval
* javelin-reactornode
* javelin-install
* javelin-util
* @javelin
*/
JX.install('RDOM', {
statics : {
_time : null,
/**
* DynVal of the current time in milliseconds.
*/
time : function() {
if (JX.RDOM._time === null) {
var time = new JX.ReactorNode([], JX.id);
window.setInterval(function() {
time.forceSendValue(JX.now());
}, 100);
JX.RDOM._time = new JX.DynVal(time, JX.now());
}
return JX.RDOM._time;
},
/**
* Given a DynVal[String], return a DOM text node whose value tracks it.
*/
$DT : function(dyn_string) {
var node = document.createTextNode(dyn_string.getValueNow());
dyn_string.transform(function(s) { node.data = s; });
return node;
},
_recvEventPulses : function(node, event) {
var reactor_node = new JX.ReactorNode([], JX.id);
var no_path = null;
JX.DOM.listen(
node,
event,
no_path,
JX.bind(reactor_node, reactor_node.forceSendValue)
);
reactor_node.setGraphID(JX.DOM.uniqID(node));
return reactor_node;
},
_recvChangePulses : function(node) {
return JX.RDOM._recvEventPulses(node, 'change').transform(function() {
return node.value;
});
},
/**
* Sets up a bidirectional DynVal for a node.
* @param node :: DOM Node
* @param inPulsesFn :: DOM Node -> ReactorNode
* @param inDynValFn :: DOM Node -> ReactorNode -> DynVal
* @param outFn :: ReactorNode -> DOM Node
*/
_bidi : function(node, inPulsesFn, inDynValFn, outFn) {
var inPulses = inPulsesFn(node);
var inDynVal = inDynValFn(node, inPulses);
outFn(inDynVal.getChanges(), node);
inDynVal.getChanges().listen(inPulses);
return inDynVal;
},
/**
* ReactorNode[String] of the incoming values of a radio group.
* @param Array of DOM elements, all the radio buttons in a group.
*/
_recvRadioPulses : function(buttons) {
var ins = [];
for (var ii = 0; ii < buttons.length; ii++) {
ins.push(JX.RDOM._recvChangePulses(buttons[ii]));
}
return new JX.ReactorNode(ins, JX.id);
},
/**
* DynVal[String] of the incoming values of a radio group.
* pulses is a ReactorNode[String] of the incoming values of the group
*/
_recvRadio : function(buttons, pulses) {
var init = '';
for (var ii = 0; ii < buttons.length; ii++) {
if (buttons[ii].checked) {
init = buttons[ii].value;
break;
}
}
return new JX.DynVal(pulses, init);
},
/**
* Send the pulses from the ReactorNode[String] to the radio group.
* Sending an invalid value will result in a log message in __DEV__.
*/
_sendRadioPulses : function(rnode, buttons) {
return rnode.transform(function(val) {
var found;
if (__DEV__) {
found = false;
}
for (var ii = 0; ii < buttons.length; ii++) {
if (buttons[ii].value == val) {
buttons[ii].checked = true;
if (__DEV__) {
found = true;
}
}
}
if (__DEV__) {
if (!found) {
throw new Error("Mismatched radio button value");
}
}
});
},
/**
* Bidirectional DynVal[String] for a radio group.
* Sending an invalid value will result in a log message in __DEV__.
*/
radio : function(input) {
return JX.RDOM._bidi(
input,
JX.RDOM._recvRadioPulses,
JX.RDOM._recvRadio,
JX.RDOM._sendRadioPulses
);
},
/**
* ReactorNode[Boolean] of the values of the checkbox when it changes.
*/
_recvCheckboxPulses : function(checkbox) {
return JX.RDOM._recvChangePulses(checkbox).transform(function(val) {
return Boolean(val);
});
},
/**
* DynVal[Boolean] of the value of a checkbox.
*/
_recvCheckbox : function(checkbox, pulses) {
return new JX.DynVal(pulses, Boolean(checkbox.checked));
},
/**
* Send the pulses from the ReactorNode[Boolean] to the checkbox
*/
_sendCheckboxPulses : function(rnode, checkbox) {
return rnode.transform(function(val) {
if (__DEV__) {
if (!(val === true || val === false)) {
throw new Error("Send boolean values to checkboxes.");
}
}
checkbox.checked = val;
});
},
/**
* Bidirectional DynVal[Boolean] for a checkbox.
*/
checkbox : function(input) {
return JX.RDOM._bidi(
input,
JX.RDOM._recvCheckboxPulses,
JX.RDOM._recvCheckbox,
JX.RDOM._sendCheckboxPulses
);
},
/**
* ReactorNode[String] of the changing values of a text input.
*/
_recvInputPulses : function(input) {
// This misses advanced changes like paste events.
var live_changes = [
JX.RDOM._recvChangePulses(input),
JX.RDOM._recvEventPulses(input, 'keyup'),
JX.RDOM._recvEventPulses(input, 'keypress'),
JX.RDOM._recvEventPulses(input, 'keydown')
];
return new JX.ReactorNode(live_changes, function() {
return input.value;
});
},
/**
* DynVal[String] of the value of a text input.
*/
_recvInput : function(input, pulses) {
return new JX.DynVal(pulses, input.value);
},
/**
* Send the pulses from the ReactorNode[String] to the input
*/
_sendInputPulses : function(rnode, input) {
var result = rnode.transform(function(val) {
input.value = val;
});
result.setGraphID(JX.DOM.uniqID(input));
return result;
},
/**
* Bidirectional DynVal[String] for a text input.
*/
input : function(input) {
return JX.RDOM._bidi(
input,
JX.RDOM._recvInputPulses,
JX.RDOM._recvInput,
JX.RDOM._sendInputPulses
);
},
/**
* ReactorNode[String] of the incoming changes in value of a select element.
*/
_recvSelectPulses : function(select) {
return JX.RDOM._recvChangePulses(select);
},
/**
* DynVal[String] of the value of a select element.
*/
_recvSelect : function(select, pulses) {
return new JX.DynVal(pulses, select.value);
},
/**
* Send the pulses from the ReactorNode[String] to the select.
* Sending an invalid value will result in a log message in __DEV__.
*/
_sendSelectPulses : function(rnode, select) {
return rnode.transform(function(val) {
select.value = val;
if (__DEV__) {
if (select.value !== val) {
throw new Error("Mismatched select value");
}
}
});
},
/**
* Bidirectional DynVal[String] for the value of a select.
*/
select : function(select) {
return JX.RDOM._bidi(
select,
JX.RDOM._recvSelectPulses,
JX.RDOM._recvSelect,
JX.RDOM._sendSelectPulses
);
},
/**
* ReactorNode[undefined] that fires when a button is clicked.
*/
clickPulses : function(button) {
return JX.RDOM._recvEventPulses(button, 'click').transform(function() {
return null;
});
},
/**
* ReactorNode[Boolean] of whether the mouse is over a target.
*/
_recvIsMouseOverPulses : function(target) {
var mouseovers = JX.RDOM._recvEventPulses(target, 'mouseover').transform(
function() {
return true;
});
var mouseouts = JX.RDOM._recvEventPulses(target, 'mouseout').transform(
function() {
return false;
});
return new JX.ReactorNode([mouseovers, mouseouts], JX.id);
},
/**
* DynVal[Boolean] of whether the mouse is over a target.
*/
isMouseOver : function(target) {
// Not worth it to initialize this properly.
return new JX.DynVal(JX.RDOM._recvIsMouseOverPulses(target), false);
},
/**
* ReactorNode[Boolean] of whether an element has the focus.
*/
_recvHasFocusPulses : function(target) {
var focuses = JX.RDOM._recvEventPulses(target, 'focus').transform(
function() {
return true;
});
var blurs = JX.RDOM._recvEventPulses(target, 'blur').transform(
function() {
return false;
});
return new JX.ReactorNode([focuses, blurs], JX.id);
},
/**
* DynVal[Boolean] of whether an element has the focus.
*/
_recvHasFocus : function(target) {
var is_focused_now = (target === document.activeElement);
return new JX.DynVal(JX.RDOM._recvHasFocusPulses(target), is_focused_now);
},
_sendHasFocusPulses : function(rnode, target) {
rnode.transform(function(should_focus) {
if (should_focus) {
target.focus();
} else {
target.blur();
}
return should_focus;
});
},
/**
* Bidirectional DynVal[Boolean] of whether an element has the focus.
*/
hasFocus : function(target) {
return JX.RDOM._bidi(
target,
JX.RDOM._recvHasFocusPulses,
JX.RDOM._recvHasFocus,
JX.RDOM._sendHasFocusPulses
);
},
/**
* Send a CSS class from a DynVal to a node
*/
sendClass : function(dynval, node, className) {
return dynval.transform(function(add) {
JX.DOM.alterClass(node, className, add);
});
},
/**
* Dynamically attach a set of DynVals to a DOM node's properties as
* specified by props.
* props: {left: someDynVal, style: {backgroundColor: someOtherDynVal}}
*/
sendProps : function(node, props) {
var dynvals = [];
var keys = [];
var style_keys = [];
for (var key in props) {
keys.push(key);
if (key === 'style') {
for (var style_key in props[key]) {
style_keys.push(style_key);
dynvals.push(props[key][style_key]);
node.style[style_key] = props[key][style_key].getValueNow();
}
} else {
dynvals.push(props[key]);
node[key] = props[key].getValueNow();
}
}
return JX.Reactor.lift(JX.bind(null, function(keys, style_keys, node) {
var args = JX.$A(arguments).slice(3);
for (var ii = 0; ii < args.length; ii++) {
if (keys[ii] === 'style') {
for (var jj = 0; jj < style_keys.length; jj++) {
node.style[style_keys[jj]] = args[ii];
ii++;
}
ii--;
} else {
node[keys[ii]] = args[ii];
}
}
}, keys, style_keys, node), dynvals);
}
}
});

File Metadata

Mime Type
text/x-Algol68
Expires
Wed, Dec 3, 6:37 PM (1 h, 8 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
433980
Default Alt Text
RDOM.js (10 KB)

Event Timeline