<form id='attendee'></form> <pre id='out'></pre> <button id='ba'>Payal's Grandmother Preset</button> <script id='attendeeMustache' type='text/mustache'> <p id='attending'> Can you make it? <input value="yes" type="radio" id="available" {{checked attendee.attending}}/> <label for='available'>Yes</label> <input value="no" type="radio" id='notavailable' {{checked attendee.attending}}/> <label for='notavailable'>No</label>. </p> <p> <input name="name" {{value attendee.name}} {{placeholder "name" attendee.name}}/> </p> <div id='address' {{fadeInWhen attending}}> <p id='country'> Country:</br> <input name="country" value="USA" type="radio" id='usa' {{checked attendee.country}} /> <label for='usa'>USA</label> <input name="country" value="India" type="radio" id='india' {{checked attendee.country}}/> <label for='india'>India</label> <input name="country" value="Canada" type="radio" id='canada' {{checked attendee.country}}/> <label for='canada'>Canada</label> </p> <div id='street'> <p> <input name="street" {{value attendee.street}} {{placeholder "street" attendee.street}}/> <input name="apt" {{value attendee.apt}} {{placeholder "apt" attendee.apt}}/> </p> <p id='location-units'> <input name="city" {{value attendee.city}} {{fadeInWhen cityOrStateSetOrCountryNotUSA}} {{placeholder "city" attendee.city}}/> <input name="state" {{value attendee.state}} {{fadeInWhen cityOrStateSetOrCountryNotUSA}} {{placeholder statePlaceholder attendee.state}}/> <input name="zip" {{value attendee.zip}} {{placeholder zipPlaceholder attendee.zip}}/> </p> </div> </div> </script>
setupMustacheHelpers() var attendee = new can.Observe({ country: "USA" }), placeholders = { usa: { state: "state", zip: "zip code" }, india: { state: "state", zip: "postal code" }, canada: { state: "province", zip: "postal code" } }, countryPlaceholders = function(){ return placeholders[(attendee.attr('country')).toLowerCase()] }; $("#attendee").html( can.view("attendeeMustache", { attendee: attendee, statePlaceholder: can.compute(function(){ return countryPlaceholders().state }), zipPlaceholder: can.compute(function(){ return countryPlaceholders().zip }), cityOrStateSetOrCountryNotUSA: can.compute(function(){ return attendee.attr('state') || attendee.attr('city') || ( attendee.attr('country') && attendee.attr('country') !== "USA" ); }), attending: can.compute(function(){ console.log("re-eval"); return attendee.attr('attending') === 'yes' }) })); attendee.bind("change", function(){ $("#out").text( JSON.stringify( attendee.attr() ).replace(/,/g,",\n ") ); }) $("#ba").click(function(){ attendee.attr({ name: "Payal's Grandmother", attending: "yes", country: "India", street: "1234 Punjab St", apt: "4u", city: "Hyderabad", state: "Andhra Pradesh", zip: "500001" }) }) function setupMustacheHelpers() { var placeholderSupported = false// "placeholder" in document.createElement("input"); // Adds a placeholder for browsers that don't support it Placeholder = can.Control({ init: function(element, options) { if( placeholderSupported ) { this.element.attr('placeholder', this.options.placeholder() ); } else { if( this.element.val() === '' ) { this.addPlaceholder(); } else { this.changed = true; } } }, addPlaceholder: function(){ this.element.val(this.options.placeholder()) .addClass('placeholder'); this.changed = false; }, removePlaceholder: function(){ this.element.val("").removeClass('placeholder'); }, 'focus': function(el, ev) { if( ! placeholderSupported && !this.changed ) { if( this.element.val() === this.options.placeholder() ) { this.removePlaceholder(); } } }, 'blur': function(){ if( !placeholderSupported ) { if( this.element.val() === '' ) { this.addPlaceholder(); } } }, "{value} change": function(value, ev, newVal, oldVal){ if( !placeholderSupported && newVal) { this.element.removeClass('placeholder'); } }, "{placeholder} change": function(placeholder, ev, newVal, oldVal){ if( placeholderSupported ) { this.element.attr('placeholder', newVal) } else { if( !this.changed && !this.isFocused() ) { this.element.val(newVal); } } }, "change" : function(){ this.changed = (this.element.val() !== ""); }, isFocused: function(){ return document.activeElement === this.element[0]; } }); can.Mustache.registerHelper('placeholder', function(placeholder, value){ return function(el){ if(typeof placeholder === "string"){ placeholder = can.compute(placeholder); } new Placeholder(el, { placeholder: placeholder, value: value }); } }); // adds a checked property if value matches the value // of the current element var Checked = can.Control({ init: function(){ this.check() }, "{value} change": "check", check: function(){ if(this.options.value() === this.element.val()){ this.element.prop("checked", true) } else { this.element.prop("checked", false) } }, "change": function(){ if(this.element.is(":checked")){ this.options.value(this.element.val()) } } }) can.Mustache.registerHelper('checked', function(value){ return function(el){ new Checked(el, {value: value}); } }); // 2-way binds an element and value var Value = can.Control({ init: function(){ this.set() }, "{value} change": "set", set: function(){ this.element.val(this.options.value()) }, "change": function(){ this.options.value(this.element.val()) } }); can.Mustache.registerHelper('value', function(value){ return function(el){ new Value(el, {value: value}); } }); // Fades an element in when a value is truthy var FadeInWhen = can.Control({ init: function(){ if(this.options.value()){ this.element.show(); } else { this.element.hide() } }, "{value} change": function(value, ev, newVal){ if( newVal ) { this.element.fadeIn(); } else { this.element.hide() } } }); can.Mustache.registerHelper('fadeInWhen', function(value){ return function(el){ console.log("fadeInWhen",el,value()) new FadeInWhen(el, {value: value}); } }); };
@import url(http://fonts.googleapis.com/css?family=Lato:400); * { font-family: 'Lato', sans-serif; font-size: 16px; text-shadow: 0 1px 0 #ffffff; } input, textarea, select { -moz-box-shadow: inset 2px 2px 3px rgba(0, 0, 0, 0.07); -webkit-box-shadow: inset 2px 2px 3px rgba(0, 0, 0, 0.07); box-shadow: inset 2px 2px 3px rgba(0, 0, 0, 0.07); border: 1px solid #ccc; padding: 3px; -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; font-size: 12px; } #attendee input:focus, textarea:focus { -moz-box-shadow: inset 2px 2px 3px rgba(0, 0, 0, 0.07); -webkit-box-shadow: inset 2px 2px 3px rgba(0, 0, 0, 0.07); box-shadow: inset 2px 2px 3px rgba(0, 0, 0, 0.07); border: 1px solid #969595; background-color: #fffef2; } ::-webkit-input-placeholder { color: #ccc;font-size: 12px; } .placeholder { color: #ccc;font-size: 12px; } :-moz-placeholder { color: #ccc; font-size: 12px;} ::-moz-placeholder { color: #ccc; font-size: 12px;} :-ms-input-placeholder { color: #ccc; font-size: 12px;} p {margin: 12px; } [name=zip], [name=apt] { width: 75px; } [name=state] { width: 100px; } button { position: fixed; right: 0px; top: 0px; } pre { margin:10px; padding: 10px; background-color: #d7e5fd; color: #011a49; font-size: 11px; font-family: "Courier New", Courier, mono; } button { margin: 10px; background-color: #165489; color: #fff; font-size: 12px; border: 1px solid #02325b; -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; text-shadow: 0 -1px 0 #02325b; } button:hover { background-color: #02325b; }