Skip to content

Instantly share code, notes, and snippets.

@podhmo
Created March 28, 2015 00:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save podhmo/4ee07930ec610ed23c11 to your computer and use it in GitHub Desktop.
Save podhmo/4ee07930ec610ed23c11 to your computer and use it in GitHub Desktop.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<h1> form sample</h1>
<form>
<input type="submit">
<div>event
<input name="name" placeholder="event name"/>
</div>
<div collection="participants">
<div>user:
<input name="name" placeholder="user name">
<input age="age" placeholder="0" type="number">
<button tabindex="-1" type="button" data-role="remove" data-target="participants">-</button>
</div>
</div>
<button type="button" data-role="add" data-target="participants">+</button>
</form>
<p>output</p>
<pre id="outputArea"></pre>
<script type="text/javascript" src="./walker.js"></script>
<script type="text/javascript">
var form = document.querySelector("form");
form.addEventListener("submit", function(ev){
var r = new Walker(walk).walkNode(ev.currentTarget);
document.querySelector("#outputArea").textContent = JSON.stringify(r, null, 2);
ev.preventDefault();
});
new ActionRegister(form).bind();
</script>
</body>
</html>
'use strict';
function Walker(walk){
this.walk = walk;
}
Walker.prototype.walkSelect = function(node, r){
var name = node.getAttribute("name");
var cs = node.querySelectorAll("option");
if(node.hasAttribute("multiple")){
r[name] = [];
for(var i=0,j=cs.length; i<j; i++){
if(cs[i].hasAttribute("selected")){
r[name] = cs[i].value;
}
}
}else{
for(var i=0,j=cs.length; i<j; i++){
if(cs[i].hasAttribute("selected")){
r[name] = cs[i].value;
return;
}
}
}
};
Walker.prototype.walkInput = function(node, r){
var type = node.getAttribute("type");
if(type === "submit"){
return;
} else if(type === "checkbox"){
var name = node.getAttribute("name");
if(!r[name]){
r[name] = [];
}
if(node.hasAttribute("checked")){
r[name].push(node.value);
}
}else if(type === "radio"){
if(node.hasAttribute("checked")){
r[node.getAttribute("name")] = node.value;
}
}else{
r[node.getAttribute("name")] = node.value;
}
};
Walker.prototype.walkScope = function(node){
var r = {};
var cs = node.children;
for(var i=0,j=cs.length; i<j; i++){
walk(this, cs[i], r);
}
return r;
};
Walker.prototype.walkCollection = function(node){
var r = [];
var cs = node.children;
for(var i=0,j=cs.length; i<j; i++){
var sub = {};
walk(this, cs[i], sub);
r.push(sub);
}
return r;
};
Walker.prototype.walkNode = function(node){
var r = {};
walk(this, node, r);
return r;
};
Walker.prototype.extract = function(form){
var input = document.createElement("input");
input.setAttribute("type", "hidden");
input.setAttribute("value", JSON.stringify(this.walkNode(form)));
form.appendChild(input);
};
function walk(walker, node, r){
if(node.hasAttribute("disabled")){
return;
}
if(node.nodeName === "INPUT"){
walker.walkInput(node, r);
}else if(node.nodeName === "SELECT"){
walker.walkSelect(node, r);
}else if(node.hasAttribute("scope")){
r[node.getAttribute("scope")] = walker.walkScope(node);
}else if(node.hasAttribute("collection")){
r[node.getAttribute("collection")] = walker.walkCollection(node);
}else {
var cs = node.children;
for(var i=0,j=cs.length; i<j; i++){
walk(walker, cs[i], r);
}
}
}
function ActionRegister(root){
this.root = root;
this.state = {};
}
ActionRegister.prototype.addItem = function(ev){
var src = ev.target;
if((src.nodeName === "BUTTON") && (src.getAttribute("data-role") === "add")){
var target = src.getAttribute("data-target");
var parent = document.querySelector("form [collection='{}']".replace("{}", target));
var newitem;
if(!!this.state[target]){
newitem = this.state[target].cloneNode(true);
}else{
newitem = parent.querySelector(":first-Child").cloneNode(true);
}
var cs = newitem.querySelectorAll("input");
for(var i=0,j=cs.length; i<j; i++){
cs[i].value = "";
}
parent.appendChild(newitem);
}
};
ActionRegister.prototype.removeItem = function(ev){
var src = ev.target;
if((src.nodeName === "BUTTON") && (src.getAttribute("data-role") === "remove")){
var target = src.getAttribute("data-target");
while(!(src.parentElement.hasAttribute("collection"))){
src = src.parentElement;
}
this.state[target] = src.parentElement.removeChild(src);
}
};
ActionRegister.prototype.bind = function(node){
node = node || this.root;
node.addEventListener("click", this.addItem.bind(this));
node.addEventListener("click", this.removeItem.bind(this));
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment