mirror of
https://github.com/getformwork/formwork.git
synced 2025-01-17 21:49:04 +01:00
Add duration field
This commit is contained in:
parent
c98bb5833f
commit
95f7cf6c97
2
admin/assets/css/admin-dark.min.css
vendored
2
admin/assets/css/admin-dark.min.css
vendored
File diff suppressed because one or more lines are too long
2
admin/assets/css/admin.min.css
vendored
2
admin/assets/css/admin.min.css
vendored
File diff suppressed because one or more lines are too long
2
admin/assets/js/app.min.js
vendored
2
admin/assets/js/app.min.js
vendored
File diff suppressed because one or more lines are too long
213
admin/assets/js/src/components/durationinput.js
Normal file
213
admin/assets/js/src/components/durationinput.js
Normal file
@ -0,0 +1,213 @@
|
||||
import Utils from './utils';
|
||||
|
||||
export default function DurationInput(input, options) {
|
||||
var defaults = {
|
||||
unit: 'seconds',
|
||||
display: ['years', 'months', 'weeks', 'days', 'hours', 'minutes', 'seconds'],
|
||||
labels: {
|
||||
years: ['year', 'years'],
|
||||
months: ['month', 'months'],
|
||||
weeks: ['week', 'weeks'],
|
||||
days: ['day', 'days'],
|
||||
hours: ['hour', 'hours'],
|
||||
minutes: ['minute', 'minutes'],
|
||||
seconds: ['second', 'seconds']
|
||||
}
|
||||
};
|
||||
|
||||
var TIME_INTERVALS = {
|
||||
years: 60 * 60 * 24 * 365,
|
||||
months: 60 * 60 * 24 * 30,
|
||||
weeks: 60 * 60 * 24 * 7,
|
||||
days: 60 * 60 * 24,
|
||||
hours: 60 * 60,
|
||||
minutes: 60,
|
||||
seconds: 1
|
||||
};
|
||||
|
||||
var field, hiddenInput;
|
||||
|
||||
var innerInputs = {};
|
||||
|
||||
var labels = {};
|
||||
|
||||
options = Utils.extendObject({}, defaults, options);
|
||||
|
||||
createField();
|
||||
|
||||
function secondsToIntervals(seconds) {
|
||||
var intervals = {};
|
||||
var t;
|
||||
for (t in TIME_INTERVALS) {
|
||||
if (Object.prototype.hasOwnProperty.call(TIME_INTERVALS, t) && options.display.indexOf(t) !== -1) {
|
||||
intervals[t] = Math.floor(seconds / TIME_INTERVALS[t]);
|
||||
seconds -= intervals[t] * TIME_INTERVALS[t];
|
||||
}
|
||||
}
|
||||
return intervals;
|
||||
}
|
||||
|
||||
function intervalsToSeconds(intervals) {
|
||||
var seconds = 0;
|
||||
var i;
|
||||
for (i in intervals) {
|
||||
if (Object.prototype.hasOwnProperty.call(intervals, i) && Object.prototype.hasOwnProperty.call(TIME_INTERVALS, i)) {
|
||||
seconds += intervals[i] * TIME_INTERVALS[i];
|
||||
}
|
||||
}
|
||||
return seconds;
|
||||
}
|
||||
|
||||
function updateHiddenInput() {
|
||||
var intervals = {};
|
||||
var seconds = 0;
|
||||
var step = 0;
|
||||
var i = 0;
|
||||
for (i in innerInputs) {
|
||||
if (Object.prototype.hasOwnProperty.call(innerInputs, i)) {
|
||||
intervals[i] = innerInputs[i].value;
|
||||
}
|
||||
}
|
||||
seconds = intervalsToSeconds(intervals);
|
||||
if (hiddenInput.step) {
|
||||
step = hiddenInput.step * TIME_INTERVALS[options.unit];
|
||||
seconds = Math.floor(seconds / step) * step;
|
||||
}
|
||||
if (hiddenInput.min) {
|
||||
seconds = Math.max(seconds, hiddenInput.min);
|
||||
}
|
||||
if (hiddenInput.max) {
|
||||
seconds = Math.min(seconds, hiddenInput.max);
|
||||
}
|
||||
hiddenInput.value = Math.round(seconds / TIME_INTERVALS[options.unit]);
|
||||
}
|
||||
|
||||
function updateInnerInputs() {
|
||||
var intervals = secondsToIntervals(hiddenInput.value * TIME_INTERVALS[options.unit]);
|
||||
var i;
|
||||
for (i in innerInputs) {
|
||||
if (Object.prototype.hasOwnProperty.call(innerInputs, i)) {
|
||||
innerInputs[i].value = intervals[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function updateInnerInputsLength() {
|
||||
var i;
|
||||
for (i in innerInputs) {
|
||||
if (Object.prototype.hasOwnProperty.call(innerInputs, i)) {
|
||||
innerInputs[i].style.width = Math.max(3, innerInputs[i].value.length + 2) + 'ch';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function updateLabels() {
|
||||
var i;
|
||||
for (i in innerInputs) {
|
||||
if (Object.prototype.hasOwnProperty.call(innerInputs, i)) {
|
||||
labels[i].innerHTML = options.labels[i][parseInt(innerInputs[i].value) === 1 ? 0 : 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function createInnerInputs(intervals, steps) {
|
||||
var wrap, name, innerInput, label, i;
|
||||
|
||||
field = document.createElement('div');
|
||||
field.className = 'duration-input';
|
||||
|
||||
for (i = 0; i < options.display.length; i++) {
|
||||
name = options.display[i];
|
||||
wrap = document.createElement('span');
|
||||
wrap.className = 'duration-' + name;
|
||||
innerInput = document.createElement('input');
|
||||
innerInput.type = 'number';
|
||||
innerInput.value = intervals[name] || 0;
|
||||
innerInput.style.width = Math.max(3, innerInput.value.length + 2) + 'ch';
|
||||
if (steps[name] > 1) {
|
||||
innerInput.step = steps[name];
|
||||
}
|
||||
if (input.disabled) {
|
||||
innerInput.disabled = true;
|
||||
}
|
||||
innerInputs[name] = innerInput;
|
||||
innerInput.addEventListener('change', function () {
|
||||
updateHiddenInput();
|
||||
updateInnerInputs();
|
||||
updateInnerInputsLength();
|
||||
updateLabels();
|
||||
});
|
||||
innerInput.addEventListener('input', function () {
|
||||
updateHiddenInput();
|
||||
updateInnerInputsLength();
|
||||
updateLabels();
|
||||
});
|
||||
innerInput.addEventListener('focus', function () {
|
||||
field.classList.add('focused');
|
||||
});
|
||||
innerInput.addEventListener('blur', function () {
|
||||
field.classList.remove('focused');
|
||||
});
|
||||
wrap.addEventListener('mousedown', function (event) {
|
||||
var input = $('input', this);
|
||||
if (input && event.target !== input) {
|
||||
input.focus();
|
||||
event.preventDefault();
|
||||
}
|
||||
});
|
||||
label = document.createElement('label');
|
||||
label.innerHTML = options.labels[name][parseInt(innerInput.value) === 1 ? 0 : 1];
|
||||
labels[name] = label;
|
||||
wrap.appendChild(innerInput);
|
||||
wrap.appendChild(label);
|
||||
field.appendChild(wrap);
|
||||
}
|
||||
|
||||
field.addEventListener('mousedown', function (event) {
|
||||
if (event.target === this) {
|
||||
innerInput.focus();
|
||||
event.preventDefault();
|
||||
}
|
||||
});
|
||||
|
||||
return field;
|
||||
}
|
||||
|
||||
function createField() {
|
||||
var field, valueSeconds, stepSeconds;
|
||||
hiddenInput = document.createElement('input');
|
||||
hiddenInput.className = 'duration-hidden-input';
|
||||
hiddenInput.name = input.name;
|
||||
hiddenInput.id = input.id;
|
||||
hiddenInput.type = 'text';
|
||||
hiddenInput.value = input.value;
|
||||
hiddenInput.readOnly = true;
|
||||
hiddenInput.hidden = true;
|
||||
if (input.min) {
|
||||
hiddenInput.min = input.min;
|
||||
}
|
||||
if (input.max) {
|
||||
hiddenInput.max = input.max;
|
||||
}
|
||||
if (input.step) {
|
||||
hiddenInput.step = input.step;
|
||||
}
|
||||
if (input.required) {
|
||||
hiddenInput.required = true;
|
||||
}
|
||||
if (input.disabled) {
|
||||
hiddenInput.disabled = true;
|
||||
}
|
||||
if (input.hasAttribute('data-display')) {
|
||||
options.display = input.getAttribute('data-display').split(', ');
|
||||
}
|
||||
if (input.hasAttribute('data-unit')) {
|
||||
options.unit = input.getAttribute('data-unit');
|
||||
}
|
||||
valueSeconds = input.value * TIME_INTERVALS[options.unit];
|
||||
stepSeconds = input.step * TIME_INTERVALS[options.unit];
|
||||
field = createInnerInputs(secondsToIntervals(valueSeconds || 0), secondsToIntervals(stepSeconds || 1));
|
||||
input.parentNode.replaceChild(field, input);
|
||||
field.appendChild(hiddenInput);
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
import ArrayInput from './arrayinput';
|
||||
import DatePicker from './datepicker';
|
||||
import DurationInput from './durationinput';
|
||||
import Editor from './editor';
|
||||
import FileInput from './fileinput';
|
||||
import Form from './form';
|
||||
@ -74,6 +75,10 @@ export default {
|
||||
TagInput(element);
|
||||
});
|
||||
|
||||
$$('input[data-field=duration]').forEach(function (element) {
|
||||
DurationInput(element, Formwork.config.DurationInput);
|
||||
});
|
||||
|
||||
$$('input[type=range]').forEach(function (element) {
|
||||
RangeInput(element);
|
||||
});
|
||||
|
@ -150,6 +150,55 @@
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.duration-input {
|
||||
box-sizing: border-box;
|
||||
margin-top: 0;
|
||||
margin-bottom: $input-margin-bottom;
|
||||
padding: $input-padding-v $input-padding-h / 2;
|
||||
border: 1px solid $color-base-500;
|
||||
border-radius: $border-radius;
|
||||
font-size: $input-font-size;
|
||||
line-height: $input-line-height;
|
||||
@include user-select-none;
|
||||
}
|
||||
|
||||
.duration-input.focused {
|
||||
border-color: $color-accent-500;
|
||||
}
|
||||
|
||||
.duration-input > span {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.duration-input input {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 2rem;
|
||||
border: 0;
|
||||
background-color: $color-base-700;
|
||||
vertical-align: baseline;
|
||||
text-align: center;
|
||||
-moz-appearance: textfield;
|
||||
&::-webkit-inner-spin-button,
|
||||
&::-webkit-outer-spin-button {
|
||||
margin: 0;
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
}
|
||||
|
||||
.duration-input input:focus {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.duration-input label {
|
||||
margin: 0;
|
||||
padding: 0 0.5rem;
|
||||
}
|
||||
|
||||
.duration-hidden-input {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.title-input {
|
||||
font-size: $font-size-l;
|
||||
}
|
||||
|
@ -76,6 +76,17 @@ abstract class AbstractController
|
||||
'weekdays' => ['long' => $this->label('date.weekdays.long'), 'short' => $this->label('date.weekdays.short')],
|
||||
'months' => ['long' => $this->label('date.months.long'), 'short' => $this->label('date.months.short')]
|
||||
]
|
||||
],
|
||||
'DurationInput' => [
|
||||
'labels' => [
|
||||
'years' => $this->label('date.duration.years'),
|
||||
'months' => $this->label('date.duration.months'),
|
||||
'weeks' => $this->label('date.duration.weeks'),
|
||||
'days' => $this->label('date.duration.days'),
|
||||
'hours' => $this->label('date.duration.hours'),
|
||||
'minutes' => $this->label('date.duration.minutes'),
|
||||
'seconds' => $this->label('date.duration.seconds')
|
||||
]
|
||||
]
|
||||
])
|
||||
];
|
||||
|
@ -292,6 +292,14 @@ class Validator
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate "duration" fields
|
||||
*/
|
||||
public static function validateDuration($value, Field $field)
|
||||
{
|
||||
return static::validateNumber($value, $field);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cast a value to its correct type
|
||||
*/
|
||||
|
@ -15,6 +15,13 @@ dashboard.statistics: Statistics
|
||||
dashboard.statistics.unique-visitors: Unique Visitors
|
||||
dashboard.statistics.visits: Visits
|
||||
dashboard.welcome: Welcome
|
||||
date.duration.days: ['day', 'days']
|
||||
date.duration.hours: ['hour', 'hours']
|
||||
date.duration.minutes: ['minute', 'minutes']
|
||||
date.duration.months: ['month', 'months']
|
||||
date.duration.seconds: ['second', 'seconds']
|
||||
date.duration.weeks: ['week', 'weeks']
|
||||
date.duration.years: ['year', 'years']
|
||||
date.months.long: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']
|
||||
date.months.short: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
|
||||
date.today: Today
|
||||
|
@ -15,6 +15,13 @@ dashboard.statistics: Statistiche
|
||||
dashboard.statistics.unique-visitors: Visitatori unici
|
||||
dashboard.statistics.visits: Visite
|
||||
dashboard.welcome: Benvenuto/a
|
||||
date.duration.days: ['giorno', 'giorni']
|
||||
date.duration.hours: ['ora', 'ore']
|
||||
date.duration.minutes: ['minuto', 'minuti']
|
||||
date.duration.months: ['mese', 'mesi']
|
||||
date.duration.seconds: ['secondo', 'secondi']
|
||||
date.duration.weeks: ['settimana', 'settimane']
|
||||
date.duration.years: ['anno', 'anni']
|
||||
date.months.long: ['Gennaio', 'Febbraio', 'Marzo', 'Aprile', 'Maggio', 'Giugno', 'Luglio', 'Agosto', 'Settembre', 'Ottobre', 'Novembre', 'Dicembre']
|
||||
date.months.short: ['Gen', 'Feb', 'Mar', 'Apr', 'Mag', 'Giu', 'Lug', 'Ago', 'Set', 'Ott', 'Nov', 'Dic']
|
||||
date.today: Oggi
|
||||
|
15
admin/views/fields/duration.php
Normal file
15
admin/views/fields/duration.php
Normal file
@ -0,0 +1,15 @@
|
||||
<?= $this->insert('fields.label') ?>
|
||||
<input <?= $this->attr([
|
||||
'type' => 'number',
|
||||
'id' => $field->name(),
|
||||
'name' => $field->formName(),
|
||||
'min' => $field->get('min'),
|
||||
'max' => $field->get('max'),
|
||||
'step' => $field->get('step'),
|
||||
'value' => $field->value(),
|
||||
'required' => $field->isRequired(),
|
||||
'disabled' => $field->isDisabled(),
|
||||
'data-field' => 'duration',
|
||||
'data-display' => $field->has('display') ? implode(', ', $field->get('display')) : null,
|
||||
'data-unit' => $field->get('unit', 'seconds')
|
||||
]) ?>>
|
Loading…
x
Reference in New Issue
Block a user