JSFiddle - React, Tailwind, and code Playground
HTML
<script src="http://ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.5.2/underscore-min.js"></script>
<script type="text/html" id="validationErrorMessage">
<p data-bind="visible: field.isModified() && !field.isValid(),
text: field.error" class="validationMessage"></p>
</script>
<h1>Abstract Submission Form</h1>
<form id='AbstractForm' data-bind="submit: onSubmit">
<section>
<h3>Registration-Id:</h3>
<!--ko text: id --><!--/ko-->
<input type="hidden" name="id" data-bind="value: id">
</section>
<section>
<h3>Presentation Title:</h3>
<textarea data-bind="value: title" name="title"></textarea>
</section>
<section>
<h3>Author List:</h3>
<table id="authors">
<tr><th>Presenter</th><th>Initial</th><th>Name</th><th>Affiliations</th></tr>
<!--ko foreach: authors-->
<tr data-bind='validationOptions: { insertMessages: false }'>
<td> <!--ko text: $index() + 1 + '.' --><!--/ko-->
<input type="radio" name="presenter" data-bind="checked: $parent.presenter, value: $index()"></td>
<td><input data-bind="value: initial, attr: {name:'author['+$index()+'].initial', placeholder: $parent.authorPlaceHolder($index())[0]}"></td>
<td><input data-bind="value: name, attr:{name:'author['+$index()+'].name', placeholder: $parent.authorPlaceHolder($index())[1]}"></td>
<td><input data-bind="value: affiliations, attr:{name:'author['+$index()+'].affiliations', placeholder: $parent.authorPlaceHolder($index())[2]}"></td>
<td>
<a href="" data-bind="click: $parent.authorRemove, if:$parent.authors().length>1">remove</a>
<a href="" data-bind="click: $parent.authorUp, if:$index()>0">up</a>
...
CSS
/* リセットしてしまった見出しのサイズ調整 */
h1 {
font-size: 160%;
}
h2 {
font-size: 130%;
}
h3 {
font-size: 100%;
}
/* ここからが AbstractForm 関連 */
form#AbstractForm h3 {
margin: 20px 0 10px 0;
}
form#AbstractForm textarea[name='title'] {
width: 450px;
height: 3em;
}
input.validationError,
select.validationError,
textarea.validationError {
background-color: #fcc;
}
form#AbstractForm {
line-height: 140%;
}
form#AbstractForm input,
form#AbstractForm select,
form#AbstractForm textarea {
font-size: 100%;
}
form#AbstractForm section > :not(h3) {
margin-left: 20px;
}
form#AbstractForm table#authors tr th,
form#AbstractForm table#authors tr td,
form#AbstractForm table#affiliations tr th,
form#AbstractForm table#affiliations tr td {
padding: 0 5px 0 5px;
font-weight: normal;
}
form#AbstractForm table#authors tr th,
form#AbstractForm table#affiliations tr th {
vertical-align: top;
}
form#AbstractForm table#authors tr td:nth-child(2) input {
width: 60px;
}
form#AbstractForm table#authors tr td:nth-child(3) input {
width: 150px;
}
form#AbstractForm table#authors tr td:nth-child(4) input {
width: 80px;
}
form#AbstractForm table#affiliations tr td:nth-child(2) input {
width: 300px;
}
form#AbstractForm table#affiliations tr td:nth-child(3) input {
width: 100px;
}
form#AbstractForm section#preview div.title {
font-weight: bold;
}
form#AbstractForm section#preview div.authors,
form#AbstractForm section#preview div.affiliations {
font-style: italic;
}
form#AbstractForm section#preview > div.authors > span.presenter {
text-decoration: underline;
}
form#AbstractForm section#preview > div.authors > span.author > span.affiliations {
vertical-align: super;
font-size: small;
}
form#AbstractForm section#preview > div.authors > span.presenter > span.affiliations {
text-decoration: none !important;
}
form#AbstractForm section#preview div.affiliations span.affiliation span.number {
...
JavaScript
/*=============================================================================
Author: Eric M. Barnard - @ericmbarnard
License: MIT (http://opensource.org/licenses/mit-license.php)
Description: Validation Library for KnockoutJS
===============================================================================
*/
/*globals require: false, exports: false, define: false, ko: false */
(function (factory) {
// Module systems magic dance.
if (typeof require === "function" && typeof exports === "object" && typeof module === "object") {
// CommonJS or Node: hard-coded dependency on "knockout"
factory(require("knockout"), exports);
} else if (typeof define === "function" && define["amd"]) {
// AMD anonymous module with hard-coded dependency on "knockout"
define(["knockout", "exports"], factory);
} else {
// <script> tag: use the global `ko` object, attaching a `mapping` property
factory(ko, ko.validation = {});
}
}(function ( ko, exports ) {
if (typeof (ko) === undefined) { throw 'Knockout is required, please ensure it is loaded before loading this validation plug-in'; }
// create our namespace object
ko.validation = exports;;/*global ko: false*/
var defaults = {
registerExtenders: true,
messagesOnModified: true,
errorsAsTitle: true, // enables/disables showing of errors as title attribute of the target element.
errorsAsTitleOnModified: false, // shows the error when hovering the input field (decorateElement must be true)
messageTemplate: null,
insertMessages: true, // automatically inserts validation messages as <span></span>
parseInputAttributes: false, // parses the HTML5 validation attribute from a form element and adds that to the object
writeInputAttributes: false, // adds HTML5 input validation attributes to form elements that ko observable's are bound to
decorateElement: false, // false to keep...