can
Version:
MIT-licensed, client-side, JavaScript framework that makes building rich web applications easy.
210 lines (178 loc) • 5.66 kB
HTML
<style>
label {
display: block;
margin: 1em 0;
}
pizza-form > div {
width: 20%;
float: left;
}
</style>
<pizza-form></pizza-form>
<script src="../../node_modules/steal/steal.js" dev-bundle main="@empty" id="demo-source">
import { ObservableArray, stacheConverters, StacheElement, type } from "can";
class SelectOne extends StacheElement {
static view = `
<div>
<p>Select {{ this.listName }}:</p>
<select value:from="default"
on:change="this.update(this.listName, 'toggle', scope.element.value)">
{{
<option>{{ option }}</option>
{{/ for }}
</select>
</div>
`;
static props = {
listName: { type: type.maybeConvert(String), default: "one" },
options: type.maybeConvert(ObservableArray),
default: type.maybeConvert(String),
update: Function
};
};
customElements.define("select-one", SelectOne);
class SelectMany extends StacheElement {
static view = `
<div>
<p>Select {{ this.listName }}:</p>
{{
<label>
{{ option }}
<input
on:change="this.update(this.listName, 'toggle', option)"
type="checkbox">
</label>
{{/ for }}
</div>
`;
static props = {
listName: { type: type.maybeConvert(String), default: "many" },
options: type.maybeConvert(ObservableArray),
update: Function
};
};
customElements.define("select-many", SelectMany);
class MeatPicker extends StacheElement {
static view = `
{{ let showOptions=null }}
<div>
<label>
Vegetarian
<input
checked:bind="not( showOptions )"
on:change="this.update('meats', 'clear')"
type="checkbox">
</label>
{{
<select-many
update:from="this.update"
listName:raw="meats"
options:from="this.options">
</select-many>
{{/ if }}
</div>
`;
static props = {
update: Function
};
};
customElements.define("meat-picker", MeatPicker);
class PizzaForm extends StacheElement {
static view = `
<p>
Selected Ingredients:
{{
{{ meat }},
{{/ for }}
{{
{{ veggie }},
{{/ for }}
{{
{{ this.selectedCheese }} cheese
{{/ if }}
</p>
<div>
<select-one
listName:raw="cheese"
update:from="this.updateIngredients"
default:from="this.selectedCheese"
options:from="this.availableCheeses">
</select-one>
</div>
<div>
<meat-picker
update:from="this.updateIngredients"
options:from="this.availableMeats">
</meat-picker>
</div>
<div>
<select-many
listName:raw="vegetables"
update:from="this.updateIngredients"
options:from="this.availableVegetables">
</select-many>
</div>
`;
static props = {
availableVegetables: {
get default() {
return [ "green peppers", "mushrooms", "onion", "tomato" ];
}
},
availableMeats: {
get default() {
return [ "chicken", "sausage", "pepperoni" ];
}
},
availableCheeses: {
get default() {
return [ "cheddar", "mozzarella", "parmesan", "provolone" ];
}
},
selectedVegetables: {
type: type.maybeConvert(ObservableArray),
get default() {
return new ObservableArray();
}
},
selectedMeats: {
type: type.maybeConvert(ObservableArray),
get default() {
return new ObservableArray();
}
},
selectedCheese: { type: type.maybeConvert(String), default: "mozzarella" }
};
updateIngredients(type, action, ingredient) {
let listName = "selected" + type.slice(0, 1).toUpperCase() + type.slice(1);
let index = this[listName].indexOf(ingredient);
switch(action) {
case "add":
if (typeof this[listName] === "string") {
this[listName] = ingredient;
} else {
this[listName].push(ingredient);
}
break;
case "remove":
if (typeof this[listName] === "string") {
this[listName] = "";
} else {
this[listName].splice(index, 1);
}
break;
case "toggle":
if (index >= 0) {
this.updateIngredients(type, "remove", ingredient);
} else {
this.updateIngredients(type, "add", ingredient);
}
break;
case "clear":
this[listName] = [];
break;
}
}
};
customElements.define("pizza-form", PizzaForm);
</script>