JavaScript preprocessors can help make authoring JavaScript easier and more convenient. For instance, CoffeeScript can help prevent easy-to-make mistakes and offer a cleaner syntax and Babel can bring ECMAScript 6 features to browsers that only support ECMAScript 5.
Any URL's added here will be added as <script>
s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.
You can apply a script from anywhere on the web to your Pen. Just put a URL to it here and we'll add it, in the order you have them, before the JavaScript in the Pen itself.
If the script you link to has the file extension of a preprocessor, we'll attempt to process it before applying.
You can also link to another Pen here, and we'll pull the JavaScript from that Pen and include it. If it's using a matching preprocessor, we'll combine the code before preprocessing, so you can use the linked Pen as a true dependency.
HTML Settings
Here you can Sed posuere consectetur est at lobortis. Donec ullamcorper nulla non metus auctor fringilla. Maecenas sed diam eget risus varius blandit sit amet non magna. Donec id elit non mi porta gravida at eget metus. Praesent commodo cursus magna, vel scelerisque nisl consectetur et.
<div class="demo"></div>
$border-radius: 4px;
$color-signal: #037DE4;
$purple-dark: #1f023a;
body {
text-align: center;
padding: 4rem;
font-size: 3rem;
background: linear-gradient(to bottom right, lighten(mix($purple-dark, $color-signal, 80%), 43), lighten($purple-dark, 18)) fixed;
}
body {
background-image: linear-gradient(to right top, #0066ff, #1d50ce, #1f3b9f, #1a2873, #11164a);
}
// VARS
.divTimeSetterContainer {
box-shadow: 0px 20px 20px -15px hsla(0, 0%, 0%, 0.5);
.timeValueBorder {
display: flex;
justify-content: space-between;
align-items: center;
background-color: #fff;
border: 1px solid #999;
border-radius: $border-radius;
}
input.timePart {
text-align: right;
border: none;
font-weight: bold;
padding: 0;
cursor: text;
outline: none;
}
input.hours,
input.minutes {
width: 7rem;
}
span.hourSymbol,
span.minuteSymbol {
margin: 0 0.5em;
}
span.timeDelimiter {
text-align: center;
font-weight: bold;
}
.button-time-control {
display: flex;
flex-direction: column;
align-items: stretch;
width: 2em;
cursor: pointer;
.updownButton {
width: 2em;
text-align: center;
}
.updownButton:first-child {
border-top-right-radius: $border-radius - 1px;
border-bottom: none;
/* to remove double line */
}
.updownButton:last-child {
border-bottom-right-radius: $border-radius - 1px;
}
.updownButton i {
//font-weight: bold;
//font-size: 1em;
}
.updownButton:hover {
background-color: hsla(212, 20%, 70%, 1);
color: hsla(212, 0%, 100%, 1);
}
}
}
// Turn off standard number spinners
input[type=number]::-webkit-inner-spin-button,
input[type=number]::-webkit-outer-spin-button {
-webkit-appearance: none;
margin: 0;
}
.demo {
display: flex;
justify-content: center;
align-items: center;
}
.postfix-position {
display: none;
}
// http://www.jqueryscript.net/time-clock/User-friendly-Duration-Picker-Plugin-With-jQuery-timesetter.html
/**
* Author: Sandun Angelo Perera
* Date: 2016-11-26
* Description: jquery-timesetter is a jQuery plugin which generates a UI component which is useful to take user inputs or
* to display time values with hour and minutes in a friendly format. UI provide intutive behaviours for better user experience
* such as validations in realtime and keyboard arrow key support.
* Dependency:
* jQuery-2.2.4.min.js
* bootstrap css: https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css
*
* https://github.com/sandunangelo/jquery-timesetter
*/
(function ($)
{
/**
* Support function to construct string with padded with a given character to the left side.
*/
function padLeft(value, l, c)
{
return Array(l - value.toString().length + 1).join(c || " ") + value.toString();
};
/**
* Initialize all the time setter controls in the document.
*/
$.fn.timesetter = function (options)
{
var wrapper = $(this);
if (wrapper.find(".divTimeSetterContainer").length !== 1)
{
wrapper.html(htmlTemplate);
}
var container = wrapper.find(".divTimeSetterContainer");
saveOptions(container, options);
var btnUp = container.find('#btnUp');
var btnDown = container.find('#btnDown');
// binding events
btnUp.unbind('click').bind('click', function (event) { updateTimeValue(this, event); });
btnDown.unbind('click').bind('click', function (event) { updateTimeValue(this, event); });
var txtHours = container.find('#txtHours');
var txtMinutes = container.find('#txtMinutes');
txtHours.unbind('focusin').bind('focusin', function (event) { $(this).select(); unitChanged(this, event); });
txtMinutes.unbind('focusin').bind('focusin', function (event) { $(this).select(); unitChanged(this, event); });
txtHours.unbind('keydown').bind('keydown', function (event) { updateTimeValueByArrowKeys(this, event); });
txtMinutes.unbind('keydown').bind('keydown', function (event) { updateTimeValueByArrowKeys(this, event); });
// apply formatting for input fields
$(container).find("input[type=text]").each(function ()
{
$(this).change(function (e)
{
formatInput(e);
});
});
// set default values
if (txtHours.val().length === 0)
{
txtHours.val(padLeft($.fn.settings.hour.min.toString(), getMaxLength($.fn.settings.hour), $.fn.settings.numberPaddingChar));
}
if (txtMinutes.val().length === 0)
{
txtMinutes.val(padLeft($.fn.settings.minute.min.toString(), getMaxLength($.fn.settings.minute), $.fn.settings.numberPaddingChar));
}
var hourSymbolSpan = txtHours.siblings("span.hourSymbol:first");
hourSymbolSpan.text($.fn.settings.hour.symbol);
var minuteSymbolSpan = txtMinutes.siblings("span.minuteSymbol:first");
minuteSymbolSpan.text($.fn.settings.minute.symbol);
var postfixLabel = container.find(".postfix-position");
postfixLabel.text($.fn.settings.postfixText);
return this;
};
/**
* Capture the time unit which is about to update from events.
*/
function unitChanged(sender)
{
var container = $(sender).parents(".divTimeSetterContainer");
loadOptions(container);
unit = $(sender).data("unit");
$.fn.settings.inputHourTextbox = container.find('#txtHours');
$.fn.settings.inputMinuteTextbox = container.find('#txtMinutes');
saveOptions(container, $.fn.settings);
};
/**
* Change the time setter values from UI events.
*/
function updateTimeValue(sender)
{
var container = $(sender).parents(".divTimeSetterContainer");
loadOptions(container);
$.fn.settings.inputHourTextbox = container.find('#txtHours');
$.fn.settings.inputMinuteTextbox = container.find('#txtMinutes');
$.fn.settings.hour.value = parseInt($.fn.settings.inputHourTextbox.val());
$.fn.settings.minute.value = parseInt($.fn.settings.inputMinuteTextbox.val());
$.fn.settings.direction = $(sender).data("direction");
// validate hour and minute values
if (isNaN($.fn.settings.hour.value))
{
$.fn.settings.hour.value = $.fn.settings.hour.min;
}
if (isNaN($.fn.settings.minute.value))
{
$.fn.settings.minute.value = $.fn.settings.minute.min;
}
// update time setter by changing hour value
if (unit === "hours")
{
var oldHourValue = parseInt($($.fn.settings.inputHourTextbox).val().trim());
var newHourValue = 0;
if ($.fn.settings.direction === "decrement")
{
newHourValue = oldHourValue - $.fn.settings.hour.step;
// tolerate the wrong step number and move to a valid step
if ((newHourValue % $.fn.settings.hour.step) > 0)
{
newHourValue = (newHourValue - (newHourValue % $.fn.settings.hour.step)); // set to the previous adjacent step
}
if (newHourValue <= $.fn.settings.hour.min)
{
newHourValue = $.fn.settings.hour.min;
}
}
else if ($.fn.settings.direction === "increment")
{
newHourValue = oldHourValue + $.fn.settings.hour.step;
// tolerate the wrong step number and move to a valid step
if ((newHourValue % $.fn.settings.hour.step) > 0)
{
newHourValue = (newHourValue - (newHourValue % $.fn.settings.hour.step)); // set to the previous adjacent step
}
if (newHourValue >= $.fn.settings.hour.max)
{
newHourValue = $.fn.settings.hour.max - $.fn.settings.hour.step;
}
}
$($.fn.settings.inputHourTextbox).val(padLeft(newHourValue.toString(), getMaxLength($.fn.settings.hour), $.fn.settings.numberPaddingChar));
$(container).attr("data-hourvalue", newHourValue);
$(container).attr("data-minutevalue", newMinuteValue);
$($.fn.settings.inputHourTextbox).trigger("change").select();
}
else if (unit === "minutes") // update time setter by changing minute value
{
var oldHourValue = $.fn.settings.hour.value;
var newHourValue = oldHourValue;
var oldMinuteValue = $.fn.settings.minute.value;
var newMinuteValue = oldMinuteValue;
if ($.fn.settings.direction === "decrement")
{
newMinuteValue = oldMinuteValue - $.fn.settings.minute.step;
// tolerate the wrong step number and move to a valid step
if ((newMinuteValue % $.fn.settings.minute.step) > 0)
{
newMinuteValue = (newMinuteValue - (newMinuteValue % $.fn.settings.minute.step)); // set to the previuos adjacent step
}
if (newHourValue <= $.fn.settings.hour.min &&
oldMinuteValue <= $.fn.settings.minute.min)
{
newHourValue = $.fn.settings.hour.min;
newMinuteValue = $.fn.settings.minute.min;
}
}
else if ($.fn.settings.direction === "increment")
{
newMinuteValue = oldMinuteValue + $.fn.settings.minute.step;
// tolerate the wrong step number and move to a valid step
if ((newMinuteValue % $.fn.settings.minute.step) > 0)
{
newMinuteValue = (newMinuteValue - (newMinuteValue % $.fn.settings.minute.step)); // set to the previous adjacent step
}
if (newHourValue >= ($.fn.settings.hour.max - $.fn.settings.hour.step) &&
oldMinuteValue >= ($.fn.settings.minute.max - $.fn.settings.minute.step))
{
newHourValue = $.fn.settings.hour.max - $.fn.settings.hour.step;
newMinuteValue = $.fn.settings.minute.max - $.fn.settings.minute.step;
}
}
// change the hour value when the minute value exceed its limits
if (newMinuteValue >= $.fn.settings.minute.max && newHourValue != $.fn.settings.hour.max && newMinuteValue)
{
newMinuteValue = $.fn.settings.minute.min;
newHourValue = oldHourValue + $.fn.settings.hour.step;
}
else if (newMinuteValue < $.fn.settings.minute.min && oldHourValue >= $.fn.settings.hour.step)
{
newMinuteValue = $.fn.settings.minute.max - $.fn.settings.minute.step;
newHourValue = oldHourValue - $.fn.settings.hour.step;
}
else if (newMinuteValue < $.fn.settings.minute.min && oldHourValue < $.fn.settings.hour.step)
{
newMinuteValue = $.fn.settings.minute.min;
newHourValue = $.fn.settings.hour.min;
}
$($.fn.settings.inputHourTextbox).val(padLeft(newHourValue.toString(), getMaxLength($.fn.settings.hour), $.fn.settings.numberPaddingChar));
$($.fn.settings.inputMinuteTextbox).val(padLeft(newMinuteValue.toString(), getMaxLength($.fn.settings.minute), $.fn.settings.numberPaddingChar));
$(container).attr("data-hourvalue", newHourValue);
$(container).attr("data-minutevalue", newMinuteValue);
$($.fn.settings.inputMinuteTextbox).trigger("change").select();
saveOptions(container, $.fn.settings);
}
};
/**
* Change the time setter values from arrow up/down key events
*/
function updateTimeValueByArrowKeys(sender, event)
{
var container = $(sender).parents(".divTimeSetterContainer");
loadOptions(container);
var senderUpBtn = $(container).find("#btnUp");
var senderDownBtn = $(container).find("#btnDown");
switch (event.which)
{
case 13: // return
break;
case 37: // left
break;
case 38: // up
senderUpBtn.click();
break;
case 39: // right
break;
case 40: // down
senderDownBtn.click();
break;
default: return; // exit this handler for other keys
}
event.preventDefault(); // prevent the default action (scroll / move caret)
saveOptions(container, $.fn.settings);
$(sender).select();
};
/**
* apply sanitization to the input value and apply corrections.
*/
function formatInput(e)
{
var element = $(e.target);
var container = $(element).parents(".divTimeSetterContainer");
loadOptions(container);
var unitSettings;
if (unit === "hours")
{
unitSettings = $.fn.settings.hour;
}
else if (unit === "minutes")
{
unitSettings = $.fn.settings.minute;
}
if (!$.isNumeric(element.val()))
{
$(element).val(padLeft(unitSettings.min.toString(), getMaxLength(unitSettings), $.fn.settings.numberPaddingChar));
return false;
}
var value = parseInt(parseFloat(element.val()));
// tolerate the wrong step number and move to a valid step
// ex: user enter 20 while step is 15, auto correct to 15
if (value >= unitSettings.max)
{
value = unitSettings.max - unitSettings.step;
$(element).val(padLeft(value.toString(), getMaxLength(unitSettings), $.fn.settings.numberPaddingChar));
return false;
}
else if (value <= unitSettings.min)
{
$(element).val(padLeft(unitSettings.min.toString(), getMaxLength(unitSettings), $.fn.settings.numberPaddingChar));
return false;
}
else if (padLeft(value.toString(), getMaxLength(unitSettings), $.fn.settings.numberPaddingChar) !== $(element).val())
{
$(element).val(padLeft(value.toString(), getMaxLength(unitSettings), $.fn.settings.numberPaddingChar));
return false;
}
else if ((value % unitSettings.step) > 0)
{
value = (value - (value % unitSettings.step)); // set to the previous adjacent step
$(element).val(padLeft(value.toString(), getMaxLength(unitSettings), $.fn.settings.numberPaddingChar));
return false;
}
//if the letter is not digit then display error and don't type anything
if (e.which != 8 && e.which != 0 && (e.which < 48 || e.which > 57))
{
//display error message
return false;
}
if (value >= Math.pow(10, getMaxLength(unitSettings)))
{
$(element).val(padLeft((Math.pow(10, getMaxLength(unitSettings)) - 1).toString(), getMaxLength(unitSettings), $.fn.settings.numberPaddingChar));
return false;
}
};
/**
* get the hour value from the control.
*/
$.fn.getHoursValue = function ()
{
var container = $(this).find(".divTimeSetterContainer");
var txtHour = $(container).find("#txtHours");
if ($.isNumeric(txtHour.val()))
{
return parseInt(txtHour.val());
}
return $.fn.settings.hour.min;
};
/**
* get the minute value from the control.
*/
$.fn.getMinutesValue = function ()
{
var container = $(this).find(".divTimeSetterContainer");
var txtMinute = $(container).find("#txtMinutes");
if ($.isNumeric(txtMinute.val()))
{
return parseInt(txtMinute.val());
}
return $.fn.settings.minute.min;
};
/**
* get the total number of minutes from the control.
*/
$.fn.getTotalMinutes = function ()
{
var container = $(this).find(".divTimeSetterContainer");
var txtHour = $(container).find("#txtHours");
var txtMinute = $(container).find("#txtMinutes");
var hourValue = 0;
var minuteValue = 0;
if ($.isNumeric(txtHour.val()) && $.isNumeric(txtMinute.val()))
{
hourValue = parseInt(txtHour.val());
minuteValue = parseInt(txtMinute.val());
}
return ((hourValue * 60) + minuteValue);
};
/**
* get the postfix display text.
*/
$.fn.getPostfixText = function ()
{
var container = $(this).find(".divTimeSetterContainer");
return container.find(".postfix-position").text();
};
/**
* set the hour value to the control.
*/
$.fn.setHour = function (hourValue)
{
var container = $(this).find(".divTimeSetterContainer");
loadOptions(container);
var txtHours = $(container).find("#txtHours");
if ($.isNumeric(hourValue))
{
txtHours.val(hourValue);
}
else
{
txtHours.val(padLeft($.fn.settings.hour.min.toString(), getMaxLength($.fn.settings.hour), $.fn.settings.numberPaddingChar));
}
unit = "hours"
saveOptions(container, $.fn.settings);
txtHours.change();
return this;
};
/**
* set the minute value to the control.
*/
$.fn.setMinute = function (minuteValue)
{
var container = $(this).find(".divTimeSetterContainer");
loadOptions(container);
var txtMinute = $(container).find("#txtMinutes");
if ($.isNumeric(minuteValue))
{
txtMinute.val(minuteValue);
}
else
{
txtMinute.val(padLeft($.fn.settings.minute.min.toString(), getMaxLength($.fn.settings.minute), $.fn.settings.numberPaddingChar));
}
unit = "minutes"
saveOptions(container, $.fn.settings);
txtMinute.change();
return this;
};
/**
* set the values by calculating based on total number of minutes by caller.
*/
$.fn.setValuesByTotalMinutes = function (totalMinutes)
{
var container = $(this).find(".divTimeSetterContainer");
loadOptions(container);
var txtHour = $(container).find("#txtHours");
var txtMinute = $(container).find("#txtMinutes");
var hourValue = 0;
var minuteValue = 0;
// total minutes must be less than total minutes per day
if (totalMinutes && totalMinutes > 0 && totalMinutes < (24 * 60))
{
minuteValue = (totalMinutes % 60);
hourValue = ((totalMinutes - minuteValue) / 60);
}
txtHour.val(padLeft(hourValue.toString(), getMaxLength($.fn.settings.hour), $.fn.settings.numberPaddingChar));
txtMinute.val(padLeft(minuteValue.toString(), getMaxLength($.fn.settings.minute), $.fn.settings.numberPaddingChar));
// trigger formattings
unit = "minutes"
saveOptions(container, $.fn.settings);
txtMinute.change(); // one event is enough to do formatting one time for all the input fields
return this;
};
/**
* set the postfix display text.
*/
$.fn.setPostfixText = function (textValue)
{
var container = $(this).find(".divTimeSetterContainer");
container.find(".postfix-position").text(textValue);
return this;
};
/**
* plugin default options for the element
*/
$.fn.getDefaultSettings = function ()
{
return {
hour: {
value: 0,
min: 0,
max: 99,
step: 1,
symbol: "h"
},
minute: {
value: 0,
min: 0,
max: 60,
step: 15,
symbol: "mins"
},
direction: "increment", // increment or decrement
inputHourTextbox: null, // hour textbox
inputMinuteTextbox: null, // minutes textbox
postfixText: "", // text to display after the input fields
numberPaddingChar: '0' // number left padding character ex: 00052
};
};
/**
* plugin options for the element
*/
$.fn.settings = $.fn.getDefaultSettings();
/**
* unit is taken out from $.fn.settings to make it globally affect as currently user is concern about which unit to change.
*/
var unit = "minutes"; /* minutes or hours */
/**
* get max length based on input field options max value.
*/
function getMaxLength(unitSettings)
{
return unitSettings.max.toString().length;
};
/**
* save the element options' values as a data value within the element.
*/
function saveOptions(container, options)
{
if (options)
{
$.fn.settings = $.extend($.fn.settings, options);
}
else
{
$.fn.settings = $.fn.getDefaultSettings();
}
$(container).data('options', $.fn.settings);
return $.fn.settings;
};
/**
* load the element's option values saved as data values.
*/
function loadOptions(container)
{
var savedOptions = $(container).data('options');
if (savedOptions)
{
$.fn.settings = $.extend($.fn.settings, $(container).data('options'));
}
else
{
$.fn.settings = $.fn.getDefaultSettings();
}
return $.fn.settings;
}
/**
* plugin UI html template
*/
var htmlTemplate =
'<div class="divTimeSetterContainer">' +
'<div class="timeValueBorder">' +
'<input id="txtHours" type="text" class="timePart hours" data-unit="hours" autocomplete="off" />' +
'<span class="hourSymbol"></span>' +
'<span class="timeDelimiter">:</span>' +
'<input id="txtMinutes" type="text" class="timePart minutes" data-unit="minutes" autocomplete="off" />' +
'<span class="minuteSymbol"></span>' +
'<div class="button-time-control">' +
'<div id="btnUp" type="button" data-direction="increment" class="updownButton">' +
'<i class="glyphicon glyphicon-triangle-top"></i>' +
'</div>' +
'<div id="btnDown" type="button" data-direction="decrement" class="updownButton">' +
'<i class="glyphicon glyphicon-triangle-bottom"></i>' +
'</div>' +
'</div>' +
'</div>' +
'<label class="postfix-position"></label>' +
'</div>';
}(jQuery));
/*
On page load call the below code
*/
$(".demo").timesetter({
hour: {
value: 4,
min: 0,
max: 24,
step: 1,
symbol: ""
},
minute: {
value: 0,
min: 0,
max: 60,
step: 15,
symbol: ""
},
// increment or decrement
direction: "increment",
// hour textbox
inputHourTextbox: null,
// minutes textbox
inputMinuteTextbox: null,
// text to display after the input fields
postfixText: "",
// number left padding character ex: 00052
numberPaddingChar: '1'
});
Also see: Tab Triggers