<link rel="stylesheet" href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css">
<script src="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/js/bootstrap.js"></script>
<script src="http://underscorejs.org/underscore-min.js"></script>
<div class="container">
<h3>Requirements</h3>
We want to use Bootstrap 2.3.2 <a href="http://getbootstrap.com/2.3.2/javascript.html#popovers">popovers</a> to show a help message that relates to a specific form control. The popover should show on the right or the left of the control, whichever side has the most space. The popover is shown on users clicking on a help icon displayed next to the label. The popover hides only when users explicitely close it, but clicking on the <i>x</i> to the right of the popover title. At most, one popover should be shown; i.e. if the popover for control A is shown, and users open the help for control B, the popover for A is closed before the popover for B is shown.
<h3>Controls</h3>
<form class="xforms-form">
<div class="row">
<div class="span6">
<span class="xforms-control">
<label class="xforms-label">
<i class="icon-question-sign xforms-help"></i>
First name
</label>
<input></input>
</span>
</div>
<div class="span6">
<span class="xforms-control">
<label class="xforms-label">
<i class="icon-question-sign xforms-help"></i>
First name
</label>
<input></input>
</span>
</div>
</div>
<div class="row">
<div class="span12">
<span class="xforms-control">
<label class="xforms-label">
<i class="icon-question-sign...
CSS
/* For testing */
input, textarea { box-sizing: border-box; width: 100% }
textarea { height: 200px }
.container { margin-top: 100px; margin-bottom: 300px }
/* Part of the "real" CSS */
.popover .close {
/* Positioning of the close 'x', using padding so this also extends the clickable area */
padding: 5px 10px;
}
.popover .popover-content {
/* So we have scrollbars when necessary */
overflow: auto;
/* So the height we set in JS is correct */
box-sizing: border-box;
}
JavaScript
$('body').on('click', '.xforms-help', function() {
var controlEl = $(this).closest('.xforms-control');
showHelp(controlEl, "First name", testHelpMessage);
});
// Hide any help popover when users press escape
$(document).keyup(function(e) {
if (e.keyCode == 27) { hideHelp(); }
});
function hideHelp() {
_.each($('form.xforms-form'), function(form) {
var popoverContainer = $(form).children('.xforms-help-popover');
var previousPopover = popoverContainer.children('.popover');
if (previousPopover.is('*')) {
var previousEl = previousPopover.data('xforms-for');
previousEl.popover('destroy');
}
});
}
function showHelp(controlEl, labelText, helpText) {
// We want the arrow to point to the form field, not somewhere between the label and the field,
// hence here we look for the first element which is not an LHHA
var firstContentEl = (function() {
var lhhaClasses = '.xforms-label, .xforms-help, .xforms-hint, .xforms-alert';
return controlEl.children().not(lhhaClasses).first();
})();
// Position and size of element relative to which we position the popover
var scrollTop = $(document).scrollTop(); // Will this work if we're in a scrollable area?
var elOffset = firstContentEl.offset();
var elWidth = firstContentEl.outerWidth();
var elHeight = firstContentEl.outerHeight();
// Is there most space on the left or the right?
var placement = (function() {
var RequiredSpace = 300;
var space = {
left: elOffset.left,
right: $(window).width() - (elOffset.left + elWidth),
top: elOffset.top - scrollTop,
bottom: $(window).height() - (elOffset.top - scrollTop + elHeight)
}
return (space.right >= RequiredSpace || space.left >= RequiredSpace)
? space.right >= space.left ? 'right' : 'left'
: (space.top >= RequiredSpace ||...
Please Whitelist JSFiddle in your content blocker.
Help keep JSFiddle free for always by one of two ways:
Whitelist JSFiddle in your content blocker (two clicks)
Go PRO and get access to additional PRO features →
Join the 4+ million users, and keep the JSFiddle dream alive.
Ad-free
All ads in the editor and listing pages are turned completely off.
Use pre-released features
You get to try and use features (like the Palette Color Generator) months before everyone else.
Fiddle collections
Sort and categorize your Fiddles into multiple collections.
Private collections and fiddles
You can make as many Private Fiddles, and Private Collections as you wish!
Console
Debug your Fiddle with a minimal built-in JavaScript console.