JSFiddle - React, Tailwind, and code Playground
by coltrane
HTML
<div id="errors"><div class="box"><span class="icon"></span><span class="content"></span></div></div>
<form class="cms-form" action="">
<table width="800">
<tr>
<td width="30%">Name:</td>
<td><input type="text" name="name" class="cms-input-text" maxlength="127" required="required" /></td>
</tr>
<tr>
<td width="30%">Bla:</td>
<td><input type="text" name="bla" class="cms-input-text" maxlength="127" required="required" /></td>
</tr>
<tr>
<td>Image:</td>
<td><textarea name="icon" class="cms-input-file" data-file-resource="images" data-options="{"min":1,"max":3}">/location-to-image.png</textarea></td>
</tr>
<tr>
<td></td>
<td><input type="submit" value="Next"/></td>
</tr>
</table>
</form>
CSS
#errors {
position: absolute;
width: 100%;
display: none;
}
#errors > .box {
position: relative;
width: 200px;
z-index: 1000;
background: white;
border: 1px solid #ccc;
border-radius: 10px;
padding: 5px;
font-size: 1em;
}
#errors > .box > .content {
display: inline;
line-height: 1.2em;
}
#errors > .box > .icon {
display: inline-block;
width: 24px; height: 24px;
vertical-align: middle;
background: url('http://b.dryicons.com/images/icon_sets/coquette_icons_set/png/24x24/warning.png')
}
JavaScript
$('textarea[name=icon]').on('customValidate', function(evt, reporter) {
var options = $(this).data('options');
// ... your validation here ...
// for example:
var txt = $(this).val();
if( txt.length < options.min ) {
reporter.reportValidationError('please add more');
}
if( txt.length > options.max ) {
reporter.reportValidationError('too many. please remove some.');
}
})
$('form.cms-form').on('submit', function(evt) {
var frm = $(this);
var allElements = $(this.elements);
hideValidationErrors();
var errors = [];
var arg = {
reportValidationError : function( msg ) {
errors.push({
msg: msg,
element: arg.element,
});
},
form : this,
element : null,
};
allElements.each(function(i, el) {
arg.element = el;
$(el).trigger('customValidate', [ arg ]);
});
if( errors.length !== 0 ) {
showValidationErrors(errors);
return false;
}
return true;
});
function hideValidationErrors() {
var el = $('#errors');
el.fadeOut(100);
}
function showValidationErrors( errs ) {
if( !errs.length ) { return; }
// show only the first error, and position it near the
// relevant form element.
var el = $('#errors');
var err = errs[0];
var contentEl = el.find('.content');
contentEl.empty().text(err.msg);
var target = $(err.element).focus();
var extents = target.offset();
extents.right = target.width()+extents.left;
extents.bottom = target.height()+extents.top;
console.dir(target);
el.css({
top: extents.bottom +1,
left: extents.left +3,
});
el.stop().fadeIn(100);
var n = '.'+Math.floor(Math.random()*0xffffffff);
var frm = $(target[0].form);
console.log('frm', frm, n);
frm.on('change'+n +' input'+n +' keydown'+n, '*', _hideErrs)
.on('focus'+n, '*',...