Just to add: I’m still not entirely clear on why you want a custom docfield type.
Docfield types are complicated. Making a new one would require you to define behavior not just for the UI but also for the database, the object relational model, the api, the form customization app, etc.
It sounds like the data structure you need is already described by the Time
docfield, and it’s just the desk interface you don’t like. If that’s the case, you’ll have a much easier time just building your own widget than you will building a whole new docfield type.
A very quick proof of concept:
Here, I’m using the regular Time
docfield type, but I’m rendering a custom control widget with two dropdowns if options
is set to “Custom”. This is roughly what @brian_pond described above. You just have to run this code somewhere in your app (or, for testing, in the console).
frappe.ui.form.ControlTime = class ControlTimeCustom extends frappe.ui.form.ControlTime {
make_input() {
if (this.df.options === 'Custom') {
console.log(this.value)
const hours = ['00', '01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11',
'12', '13', '14', '15', '16', '17', '18', '19', '20', '21', '22', '23']
const minutes = ['00', '15', '30', '45']
this.$input = $(`
<div>
<select name="hours">
${hours.map(h => '<option>' + h + '</option>').join('')}
</select>
<span>:</span>
<select name="minutes">
${minutes.map(m => '<option>' + m + '</option>').join('')}
</select>
</div>
`).prependTo(this.input_area);
this.set_input_attributes();
this.input = this.$input.get(0);
this.has_input = true;
this.bind_change_event();
} else {
super.make_input()
}
}
bind_change_event() {
if (this.df.options === 'Custom') {
const change_handler = (e) => {
let value = this.get_input_value()
this.parse_validate_and_set_in_model(value, e);
};
this.$input.find('select').on("change", change_handler);
} else {
super.bind_change_event()
}
}
get_input_value() {
if (this.df.options === 'Custom') {
return (
(this.$input.find('select[name="hours"]').val() ?? '00') +
':' +
(this.$input.find('select[name="minutes"]').val() ?? '00')
)
} else {
return super.get_input_value();
}
}
set_input(value) {
this.last_value = this.value;
this.value = value;
this.set_formatted_input(value);
this.set_disp_area(value);
this.set_mandatory && this.set_mandatory(value);
if (this.df.options === 'Custom') {
const currentValue = this.value?.split(':')?.map(n => n.padStart(2, 0))
this.$input.find('select[name="hours"]').val(currentValue?.[0] ?? '00')
this.$input.find('select[name="minutes"]').val(currentValue?.[1] ?? '00')
}
}
}