From 9326435924e04e7ba8b5424c49b9d544f7634374 Mon Sep 17 00:00:00 2001 From: Luka Stocker Date: Fri, 29 Sep 2023 10:02:03 +0200 Subject: [PATCH] UI: solve issue regarding 'disabled' datetime... .. Remove unused JavaScript and import. --- Modules/Test/test/ScoreSettingsTest.php | 5 +- Services/Form/js/Form.js | 900 +++++++++--------- .../Component/Input/Field/Renderer.php | 52 +- src/UI/examples/Input/Field/DateTime/base.php | 5 +- .../templates/default/Input/tpl.datetime.html | 7 +- src/UI/templates/js/Input/Field/duration.js | 36 - .../Input/Field/DateTimeInputTest.php | 23 +- .../Input/Field/DurationInputTest.php | 12 +- 8 files changed, 480 insertions(+), 560 deletions(-) delete mode 100644 src/UI/templates/js/Input/Field/duration.js diff --git a/Modules/Test/test/ScoreSettingsTest.php b/Modules/Test/test/ScoreSettingsTest.php index a801894c56ef..2d69c04a93b2 100644 --- a/Modules/Test/test/ScoreSettingsTest.php +++ b/Modules/Test/test/ScoreSettingsTest.php @@ -298,9 +298,8 @@ public function testScoreSettingsSectionSummary(): void
-
- - +
+
diff --git a/Services/Form/js/Form.js b/Services/Form/js/Form.js index 7c74e3483f57..10fc9b4cc040 100644 --- a/Services/Form/js/Form.js +++ b/Services/Form/js/Form.js @@ -1,459 +1,443 @@ -il.Form = { - - duration : 150, - - items: {}, - - escapeSelector: function(str) { - return str.replace(/([;&,\.\+\*\~':"\!\^#$%@\[\]\(\)=>\|])/g, '\\$1'); - }, - - sub_active: [], // active sub forms for each context - - initItem: function (id, cfg) { - il.Form.items[id] = cfg; - }, - - //ad - // General functions - // - - // init - init: function () { - $(() => { - il.Form.initLinkInput(); - il.Form.registerFileUploadInputEventTrigger(); - }); - }, - - registerFileUploadInputEventTrigger: function(selectorPrefix = '') { - - - /* experimental: bootstrap'ed file upload */ - - // see http://www.abeautifulsite.net/whipping-file-inputs-into-shape-with-bootstrap-3/ - - // trigger event on fileselect - $(document).on('change', selectorPrefix + '.btn-file :file', function() { - var input = $(this), - numFiles = input.get(0).files ? input.get(0).files.length : 1, - label = input.val().replace(/\\/g, '/').replace(/.*\//, ''); - input.trigger('fileselect', [numFiles, label]); - }); - - // display selected file name - $(selectorPrefix + '.btn-file :file').on('fileselect', function(event, numFiles, label) { - var input = $(this).parents('.input-group').find(':text'); - if( input.length ) { - input.val(label); - } - }); - - }, - - // hide sub forms - hideSubForm: function (id) { - id = il.Form.escapeSelector(id); - $("#" + id)./*css('overflow', 'hidden').*/css('height', '0px').css('display', 'none'); - }, - - // show Subform - showSubForm: function (id, cont_id, cb) { - var nh, obj, k, m; - - id = il.Form.escapeSelector(id); - cont_id = il.Form.escapeSelector(cont_id); - - console.log(id); - console.log(cont_id); - - if (cb == null) { - il.Form.sub_active[cont_id] = id; - } else { - if (cb.checked) { - il.Form.sub_active[cont_id] = id; - } else { - il.Form.sub_active[cont_id] = null; - } - } - - console.log(il.Form.sub_active); - - var parent_subform = $("#" + cont_id).parents(".ilSubForm")[0]; - - console.log("close..."); - $("#" + cont_id + " div.ilSubForm[id!='" + id + "']").each(function() { - - console.log(this.id); - - // #18482 - check if subform is on same level as parent - if(parent_subform == $(this).parents(".ilSubForm")[0]) { - - $(this).animate({ - height: 0 - }, il.Form.duration, function () { - $(this).css('display', 'none'); - - // activated in the meantime? - for (m = 0; m < il.Form.sub_active.length; m++) { - if (il.Form.escapeSelector(this.id) == il.Form.sub_active[m]) { - $(this).css('display', ''); - } - } - $(this).css('height', 'auto'); - }); - - } - }) - console.log("...close"); - - // activate subform - obj = $("#" + id).get(0); - if (obj && obj.style.display == 'none' && (cb == null || cb.checked == true)) { - obj.style.display = ''; - obj.style.position = 'relative'; - obj.style.left = '-1000px'; - obj.style.display = 'block'; - nh = obj.scrollHeight; - obj.style.height = '0px'; - obj.style.position = ''; - obj.style.left = ''; - // obj.style.overflow = 'hidden'; - - obj.style.display = ''; - $(obj).animate({ - height: nh - }, il.Form.duration, function () { - $(this).css('height', 'auto'); - }); - - // needed for google maps - $(obj).closest("form").trigger("subform_activated"); - } - - // deactivate subform of checkbox - if (obj && (cb != null && cb.checked == false)) { - // obj.style.overflow = 'hidden'; - - $(obj).animate({ - height: 0 - }, il.Form.duration, function () { - $(this).css('display', 'none'); - // activated in the meantime? - for (k = 0; k < il.Form.sub_active.length; k++) { - if (il.Form.escapeSelector(this.id) == il.Form.sub_active[k]) { - $(this).css('display', ''); - } - } - $(this).css('height', 'auto'); - }); - } - }, - - - // - // ilLinkInputGUI - // - - initLinkInput: function () { - $("a.ilLinkInputRemove").click(function (e) { - var id = this.parentNode.id; - id = id.substr(0, id.length - 4); - $("input[name=" + il.Form.escapeSelector(id) + "_ajax_type]").val(''); - $("input[name=" + il.Form.escapeSelector(id) + "_ajax_id]").val(''); - $("input[name=" + il.Form.escapeSelector(id) + "_ajax_target]").val(''); - $("#" + il.Form.escapeSelector(id) + "_value").html(''); - $(this.parentNode).css('display', 'none'); - console.log(id); - }); - }, - - // set internal link in form item - addInternalLink: function (link, title, input_id, ev, c) { - var type, id, part, target = ""; - - input_id = il.Form.escapeSelector(input_id); - - // #10543 - IE[8] - var etarget = ev.target || ev.srcElement; - - $("#" + input_id + "_value").html($(etarget).html()); - - link = link.split(' '); - part = link[1].split('="'); - type = part[0]; - id = part[1].split('"')[0]; - if (link[2] !== undefined) { - target = link[2].split('="'); - target = target[1].split('"')[0]; - } - $("input[name=" + input_id + "_ajax_type]").val(type); - $("input[name=" + input_id + "_ajax_id]").val(id); - $("input[name=" + input_id + "_ajax_target]").val(target); - - $("#" + input_id + "_rem").css('display', 'block'); - }, - - // - // ilNumberInputGUI - // - - // initialisation for number fields - initNumericCheck: function (id, decimals_allowed) { - var current; - - $('#' + il.Form.escapeSelector(id)).keydown(function (event) { - // #10562 - var kcode = event.which; - var is_shift = event.shiftKey; - var is_ctrl = event.ctrlKey; - - if (kcode == 190 || kcode == 188) { - // decimals are not allowed - if (decimals_allowed == undefined || decimals_allowed == 0) { - event.preventDefault(); - } else { - // decimal point is only allowed once - current = $('#' + id).val(); - if ( - current.indexOf('.') > -1 || - current.indexOf(',') > -1 - ) { - event.preventDefault(); - } - } - // Allow: backspace, delete, tab, escape, and enter - } else if (kcode == 46 || kcode == 8 || kcode == 9 || kcode == 27 || kcode == 13 || - // Allow: Ctrl+A - (kcode == 65 && is_ctrl === true) || - // Allow: home, end, left, right (up [38] does not matter) - (kcode >= 35 && kcode <= 39) || - // Allow: negative values (#10652) - kcode == 173) { - // let it happen, don't do anything - return; - } else { - // Ensure that it is a number and stop the keypress (2nd block: num pad) - if (is_shift || (kcode < 48 || kcode > 57) && (kcode < 96 || kcode > 105)) { - event.preventDefault(); - } - } - }); - }, - - // - // ilDateDurationInputGUI - // - - initDateDurationPicker: function (picker_id, picker2_id, toggle_id, subform_id) { - var el = $("#"+picker_id); - var dp = $(el).data("DateTimePicker"); - var el2 = $("#"+picker2_id); - var dp2 = $(el2).data("DateTimePicker"); - var txt = $(el).find("input:text"); - var txt2 = $(el2).find("input:text"); - - - // init - - // set limit by current date of other picker - /* - if(dp2.date()) - { - dp.maxDate(dp2.date()); - } - */ - if(dp.date()) - { - dp2.minDate(dp.date()); - - // store current value for diff magic - $(el).data("DateTimePickerOld", dp.date()); - } - - - // onchange - - $(el).on("dp.change", function(e) { - - // limit to value of end picker - dp2.minDate(e.date); - - // keep diff the same - var old = $(this).data("DateTimePickerOld"); - - if(old && dp2.date() && e.date) { - var diff = dp2.date().diff(old); - dp2.date(e.date.clone().add(diff)); - } - - // keep current date for diff parsing (see above); - $(this).data("DateTimePickerOld", e.date); - - if(subform_id !== undefined) - { - il.Form.handleDateDurationPickerSubForm(txt, txt2, subform_id); - } - }); - - $(el2).on("dp.change", function(e) { - - /* - // limit to value of start picker - dp.maxDate(e.date); - */ - - if(subform_id !== undefined) - { - il.Form.handleDateDurationPickerSubForm(txt, txt2, subform_id); - } - }); - - - // subform - - if(subform_id !== undefined) - { - $(el).on("dp.hide", function(e) { - il.Form.handleDateDurationPickerSubForm(txt, txt2, subform_id); - }); - - $(el2).on("dp.hide", function(e) { - il.Form.handleDateDurationPickerSubForm(txt, txt2, subform_id); - }); - - $(txt).on("input", function(e) { - il.Form.handleDateDurationPickerSubForm(txt, txt2, subform_id); - }); - - $(txt2).on("input", function(e) { - il.Form.handleDateDurationPickerSubForm(txt, txt2, subform_id); - }); - } - - - // toggle - - if(toggle_id) - { - var toggle = $("#"+toggle_id); - var full_format = dp.format(); - - - // init - - if($(toggle).prop("checked")) { - var format = dp.format(); - dp.format(format.substr(0, 10)); - format = dp2.format(); - dp2.format(format.substr(0, 10)); - } - - - // onchange - - $(toggle).change(function(e) { - - if(!$(this).prop("checked")) { - dp.format(full_format); - dp2.format(full_format); - } - else { - var short_format = full_format.substr(0, 10); - dp.format(short_format); - dp2.format(short_format); - } - - }); - } - }, - - handleDateDurationPickerSubForm: function(el, el2, subform_id) { - if($(el).val() || $(el2).val()) - { - $("#" + subform_id).show(); - } - else - { - $("#" + subform_id).hide(); - } - }, - - initDatePicker: function (picker_id, subform_id) { - var el = $("#"+picker_id); - var dp = $(el).data("DateTimePicker"); - var txt = $(el).find("input:text"); - - // onchange - $(el).on("dp.change", function(e) { - if(subform_id !== undefined) - { - il.Form.handleDatePickerSubForm(txt, subform_id); - } - }); - - // subform - if(subform_id !== undefined) - { - $(el).on("dp.hide", function(e) { - il.Form.handleDatePickerSubForm(txt, subform_id); - }); - - $(txt).on("input", function(e) { - il.Form.handleDatePickerSubForm(txt, subform_id); - }); - } - }, - - handleDatePickerSubForm: function(el, subform_id) { - if($(el).val()) - { - $("#" + subform_id).show(); - } - else - { - $("#" + subform_id).hide(); - } - }, - - //Tiny textarea char. counter - showCharCounterTinymce: function(ed) { - //var content_raw = ed.getContent({ format: 'raw' }); // whitespaces and br issues. (first whitespace creates br etc.) - var content_raw = ed.getContent({ format: 'raw' }); - var content = content_raw.replace(/<\/?[^>]+(>|$)/g, ""); - // #20630, #20674 - content = content.replace(/ /g, " "); - content = content.replace(/</g, "<"); - content = content.replace(/>/g, ">"); - content = content.replace(/&/g, "&"); - console.log(content); - var text_length = content.length; - - var max_limit = $('#textarea_feedback_'+ed.id).data("maxchars"); - if(max_limit > 0) { - var text_remaining = max_limit - text_length; - $('#textarea_feedback_'+ed.id).html(il.Language.txt("form_chars_remaining") + " " + text_remaining); - } - - }, - //normal textarea char. counter - showCharCounterTextarea: function(textarea_id, feedback_id, min_limit, max_limit) { - var text_length = $('#'+textarea_id).val().length; - if(max_limit > 0) - { - var text_remaining = max_limit - text_length; - $('#'+feedback_id).html(il.Language.txt("form_chars_remaining") +" "+ text_remaining); - return true; - } - - }, - -}; - -// init forms -il.Util.addOnLoad(il.Form.init); - -// see #27281 -$(document).on('dp.show', function(event) { - il.UI.page.fit($('.bootstrap-datetimepicker-widget')); + + +/** + * This file is part of ILIAS, a powerful learning management system + * published by ILIAS open source e-Learning e.V. + * + * ILIAS is licensed with the GPL-3.0, + * see https://www.gnu.org/licenses/gpl-3.0.en.html + * You should have received a copy of said license along with the + * source code, too. + * + * If this is not the case or you just want to try ILIAS, you'll find + * us at: + * https://www.ilias.de + * https://github.com/ILIAS-eLearning + * + ******************************************************************** */ + +il.Form = { + + duration: 150, + + items: {}, + + escapeSelector(str) { + return str.replace(/([;&,\.\+\*\~':"\!\^#$%@\[\]\(\)=>\|])/g, '\\$1'); + }, + + sub_active: [], // active sub forms for each context + + initItem(id, cfg) { + il.Form.items[id] = cfg; + }, + + // ad + // General functions + // + + // init + init() { + $(() => { + il.Form.initLinkInput(); + il.Form.registerFileUploadInputEventTrigger(); + }); + }, + + registerFileUploadInputEventTrigger(selectorPrefix = '') { + /* experimental: bootstrap'ed file upload */ + + // see http://www.abeautifulsite.net/whipping-file-inputs-into-shape-with-bootstrap-3/ + + // trigger event on fileselect + $(document).on('change', `${selectorPrefix}.btn-file :file`, function () { + const input = $(this); + const numFiles = input.get(0).files ? input.get(0).files.length : 1; + const label = input.val().replace(/\\/g, '/').replace(/.*\//, ''); + input.trigger('fileselect', [numFiles, label]); + }); + + // display selected file name + $(`${selectorPrefix}.btn-file :file`).on('fileselect', function (event, numFiles, label) { + const input = $(this).parents('.input-group').find(':text'); + if (input.length) { + input.val(label); + } + }); + }, + + // hide sub forms + hideSubForm(id) { + id = il.Form.escapeSelector(id); + $(`#${id}`)./* css('overflow', 'hidden'). */css('height', '0px').css('display', 'none'); + }, + + // show Subform + showSubForm(id, cont_id, cb) { + let nh; let obj; let k; let + m; + + id = il.Form.escapeSelector(id); + cont_id = il.Form.escapeSelector(cont_id); + + console.log(id); + console.log(cont_id); + + if (cb == null) { + il.Form.sub_active[cont_id] = id; + } else if (cb.checked) { + il.Form.sub_active[cont_id] = id; + } else { + il.Form.sub_active[cont_id] = null; + } + + console.log(il.Form.sub_active); + + const parent_subform = $(`#${cont_id}`).parents('.ilSubForm')[0]; + + console.log('close...'); + $(`#${cont_id} div.ilSubForm[id!='${id}']`).each(function () { + console.log(this.id); + + // #18482 - check if subform is on same level as parent + if (parent_subform == $(this).parents('.ilSubForm')[0]) { + $(this).animate({ + height: 0, + }, il.Form.duration, function () { + $(this).css('display', 'none'); + + // activated in the meantime? + for (m = 0; m < il.Form.sub_active.length; m++) { + if (il.Form.escapeSelector(this.id) == il.Form.sub_active[m]) { + $(this).css('display', ''); + } + } + $(this).css('height', 'auto'); + }); + } + }); + console.log('...close'); + + // activate subform + obj = $(`#${id}`).get(0); + if (obj && obj.style.display == 'none' && (cb == null || cb.checked == true)) { + obj.style.display = ''; + obj.style.position = 'relative'; + obj.style.left = '-1000px'; + obj.style.display = 'block'; + nh = obj.scrollHeight; + obj.style.height = '0px'; + obj.style.position = ''; + obj.style.left = ''; + // obj.style.overflow = 'hidden'; + + obj.style.display = ''; + $(obj).animate({ + height: nh, + }, il.Form.duration, function () { + $(this).css('height', 'auto'); + }); + + // needed for google maps + $(obj).closest('form').trigger('subform_activated'); + } + + // deactivate subform of checkbox + if (obj && (cb != null && cb.checked == false)) { + // obj.style.overflow = 'hidden'; + + $(obj).animate({ + height: 0, + }, il.Form.duration, function () { + $(this).css('display', 'none'); + // activated in the meantime? + for (k = 0; k < il.Form.sub_active.length; k++) { + if (il.Form.escapeSelector(this.id) == il.Form.sub_active[k]) { + $(this).css('display', ''); + } + } + $(this).css('height', 'auto'); + }); + } + }, + + // + // ilLinkInputGUI + // + + initLinkInput() { + $('a.ilLinkInputRemove').click(function (e) { + let { id } = this.parentNode; + id = id.substr(0, id.length - 4); + $(`input[name=${il.Form.escapeSelector(id)}_ajax_type]`).val(''); + $(`input[name=${il.Form.escapeSelector(id)}_ajax_id]`).val(''); + $(`input[name=${il.Form.escapeSelector(id)}_ajax_target]`).val(''); + $(`#${il.Form.escapeSelector(id)}_value`).html(''); + $(this.parentNode).css('display', 'none'); + console.log(id); + }); + }, + + // set internal link in form item + addInternalLink(link, title, input_id, ev, c) { + let type; let id; let part; let + target = ''; + + input_id = il.Form.escapeSelector(input_id); + + // #10543 - IE[8] + const etarget = ev.target || ev.srcElement; + + $(`#${input_id}_value`).html($(etarget).html()); + + link = link.split(' '); + part = link[1].split('="'); + type = part[0]; + id = part[1].split('"')[0]; + if (link[2] !== undefined) { + target = link[2].split('="'); + target = target[1].split('"')[0]; + } + $(`input[name=${input_id}_ajax_type]`).val(type); + $(`input[name=${input_id}_ajax_id]`).val(id); + $(`input[name=${input_id}_ajax_target]`).val(target); + + $(`#${input_id}_rem`).css('display', 'block'); + }, + + // + // ilNumberInputGUI + // + + // initialisation for number fields + initNumericCheck(id, decimals_allowed) { + let current; + + $(`#${il.Form.escapeSelector(id)}`).keydown((event) => { + // #10562 + const kcode = event.which; + const is_shift = event.shiftKey; + const is_ctrl = event.ctrlKey; + + if (kcode == 190 || kcode == 188) { + // decimals are not allowed + if (decimals_allowed == undefined || decimals_allowed == 0) { + event.preventDefault(); + } else { + // decimal point is only allowed once + current = $(`#${id}`).val(); + if ( + current.indexOf('.') > -1 + || current.indexOf(',') > -1 + ) { + event.preventDefault(); + } + } + // Allow: backspace, delete, tab, escape, and enter + } else if (kcode == 46 || kcode == 8 || kcode == 9 || kcode == 27 || kcode == 13 + // Allow: Ctrl+A + || (kcode == 65 && is_ctrl === true) + // Allow: home, end, left, right (up [38] does not matter) + || (kcode >= 35 && kcode <= 39) + // Allow: negative values (#10652) + || kcode == 173) { + // let it happen, don't do anything + + } else { + // Ensure that it is a number and stop the keypress (2nd block: num pad) + if (is_shift || (kcode < 48 || kcode > 57) && (kcode < 96 || kcode > 105)) { + event.preventDefault(); + } + } + }); + }, + + // + // ilDateDurationInputGUI + // + + initDateDurationPicker(picker_id, picker2_id, toggle_id, subform_id) { + const el = $(`#${picker_id}`); + const dp = $(el).data('DateTimePicker'); + const el2 = $(`#${picker2_id}`); + const dp2 = $(el2).data('DateTimePicker'); + const txt = $(el).find('input:text'); + const txt2 = $(el2).find('input:text'); + + // init + + // set limit by current date of other picker + /* + if(dp2.date()) + { + dp.maxDate(dp2.date()); + } + */ + if (dp.date()) { + dp2.minDate(dp.date()); + + // store current value for diff magic + $(el).data('DateTimePickerOld', dp.date()); + } + + // onchange + + $(el).on('dp.change', function (e) { + // limit to value of end picker + dp2.minDate(e.date); + + // keep diff the same + const old = $(this).data('DateTimePickerOld'); + + if (old && dp2.date() && e.date) { + const diff = dp2.date().diff(old); + dp2.date(e.date.clone().add(diff)); + } + + // keep current date for diff parsing (see above); + $(this).data('DateTimePickerOld', e.date); + + if (subform_id !== undefined) { + il.Form.handleDateDurationPickerSubForm(txt, txt2, subform_id); + } + }); + + $(el2).on('dp.change', (e) => { + /* + // limit to value of start picker + dp.maxDate(e.date); + */ + + if (subform_id !== undefined) { + il.Form.handleDateDurationPickerSubForm(txt, txt2, subform_id); + } + }); + + // subform + + if (subform_id !== undefined) { + $(el).on('dp.hide', (e) => { + il.Form.handleDateDurationPickerSubForm(txt, txt2, subform_id); + }); + + $(el2).on('dp.hide', (e) => { + il.Form.handleDateDurationPickerSubForm(txt, txt2, subform_id); + }); + + $(txt).on('input', (e) => { + il.Form.handleDateDurationPickerSubForm(txt, txt2, subform_id); + }); + + $(txt2).on('input', (e) => { + il.Form.handleDateDurationPickerSubForm(txt, txt2, subform_id); + }); + } + + // toggle + + if (toggle_id) { + const toggle = $(`#${toggle_id}`); + const full_format = dp.format(); + + // init + + if ($(toggle).prop('checked')) { + let format = dp.format(); + dp.format(format.substr(0, 10)); + format = dp2.format(); + dp2.format(format.substr(0, 10)); + } + + // onchange + + $(toggle).change(function (e) { + if (!$(this).prop('checked')) { + dp.format(full_format); + dp2.format(full_format); + } else { + const short_format = full_format.substr(0, 10); + dp.format(short_format); + dp2.format(short_format); + } + }); + } + }, + + handleDateDurationPickerSubForm(el, el2, subform_id) { + if ($(el).val() || $(el2).val()) { + $(`#${subform_id}`).show(); + } else { + $(`#${subform_id}`).hide(); + } + }, + + initDatePicker(picker_id, subform_id) { + const el = $(`#${picker_id}`); + const dp = $(el).data('DateTimePicker'); + const txt = $(el).find('input:text'); + + // onchange + $(el).on('dp.change', (e) => { + if (subform_id !== undefined) { + il.Form.handleDatePickerSubForm(txt, subform_id); + } + }); + + // subform + if (subform_id !== undefined) { + $(el).on('dp.hide', (e) => { + il.Form.handleDatePickerSubForm(txt, subform_id); + }); + + $(txt).on('input', (e) => { + il.Form.handleDatePickerSubForm(txt, subform_id); + }); + } + }, + + handleDatePickerSubForm(el, subform_id) { + if ($(el).val()) { + $(`#${subform_id}`).show(); + } else { + $(`#${subform_id}`).hide(); + } + }, + + // Tiny textarea char. counter + showCharCounterTinymce(ed) { + // var content_raw = ed.getContent({ format: 'raw' }); // whitespaces and br issues. (first whitespace creates br etc.) + const content_raw = ed.getContent({ format: 'raw' }); + let content = content_raw.replace(/<\/?[^>]+(>|$)/g, ''); + // #20630, #20674 + content = content.replace(/ /g, ' '); + content = content.replace(/</g, '<'); + content = content.replace(/>/g, '>'); + content = content.replace(/&/g, '&'); + console.log(content); + const text_length = content.length; + + const max_limit = $(`#textarea_feedback_${ed.id}`).data('maxchars'); + if (max_limit > 0) { + const text_remaining = max_limit - text_length; + $(`#textarea_feedback_${ed.id}`).html(`${il.Language.txt('form_chars_remaining')} ${text_remaining}`); + } + }, + // normal textarea char. counter + showCharCounterTextarea(textarea_id, feedback_id, min_limit, max_limit) { + const text_length = $(`#${textarea_id}`).val().length; + if (max_limit > 0) { + const text_remaining = max_limit - text_length; + $(`#${feedback_id}`).html(`${il.Language.txt('form_chars_remaining')} ${text_remaining}`); + return true; + } + }, + +}; + +// init forms +il.Util.addOnLoad(il.Form.init); + +// see #27281 +$(document).on('dp.show', function(event) { + il.UI.page.fit($('.bootstrap-datetimepicker-widget')); }); \ No newline at end of file diff --git a/src/UI/Implementation/Component/Input/Field/Renderer.php b/src/UI/Implementation/Component/Input/Field/Renderer.php index 5ab0d74693ce..6a5ba75a7656 100644 --- a/src/UI/Implementation/Component/Input/Field/Renderer.php +++ b/src/UI/Implementation/Component/Input/Field/Renderer.php @@ -44,7 +44,11 @@ class Renderer extends AbstractComponentRenderer { public const DYNAMIC_INPUT_ID_PLACEHOLDER = 'DYNAMIC_INPUT_ID'; - public const DATEPICKER_MINMAX_FORMAT = 'Y/m/d'; + public const DATETIME_DATEPICKER_MINMAX_FORMAT = 'Y-m-d\Th:m'; + public const DATE_DATEPICKER_MINMAX_FORMAT = 'Y-m-d'; + public const TYPE_DATE = 'date'; + public const TYPE_DATETIME = 'datetime-local'; + public const TYPE_TIME = 'time'; public const DATEPICKER_FORMAT_MAPPING = [ 'd' => 'DD', @@ -628,11 +632,10 @@ protected function renderDateTimeField(F\DateTime $component, RendererInterface $f = $this->getUIFactory(); if ($component->getTimeOnly() === true) { - $cal_glyph = $f->symbol()->glyph()->time("#"); $format = $component::TIME_FORMAT; + $dt_type = self::TYPE_TIME; } else { - $cal_glyph = $f->symbol()->glyph()->calendar("#"); - + $dt_type = self::TYPE_DATE; $format = $this->getTransformedDateFormat( $component->getFormat(), self::DATEPICKER_FORMAT_MAPPING @@ -640,9 +643,9 @@ protected function renderDateTimeField(F\DateTime $component, RendererInterface if ($component->getUseTime() === true) { $format .= ' ' . $component::TIME_FORMAT; + $dt_type = self::TYPE_DATETIME; } } - $tpl->setVariable("CALENDAR_GLYPH", $default_renderer->render($cal_glyph)); $config = [ 'showClear' => true, @@ -652,13 +655,20 @@ protected function renderDateTimeField(F\DateTime $component, RendererInterface ]; $config = array_merge($config, $component->getAdditionalPickerconfig()); + $tpl->setVariable("DTTYPE", $dt_type); + + $min_max_format = self::DATE_DATEPICKER_MINMAX_FORMAT; + if ($dt_type === self::TYPE_DATETIME) { + $min_max_format = self::DATETIME_DATEPICKER_MINMAX_FORMAT; + } + $min_date = $component->getMinValue(); if (!is_null($min_date)) { - $config['minDate'] = date_format($min_date, self::DATEPICKER_MINMAX_FORMAT); + $tpl->setVariable("MIN_DATE", date_format($min_date, $min_max_format)); } $max_date = $component->getMaxValue(); if (!is_null($max_date)) { - $config['maxDate'] = date_format($max_date, self::DATEPICKER_MINMAX_FORMAT); + $tpl->setVariable("MAX_DATE", date_format($max_date, $min_max_format)); } $tpl->setVariable("PLACEHOLDER", $format); @@ -667,21 +677,11 @@ protected function renderDateTimeField(F\DateTime $component, RendererInterface $tpl->setVariable("VALUE", $component->getValue()); } - $disabled = $component->isDisabled(); - - /** - * @var $component F\DateTime - */ - $component = $component->withAdditionalOnLoadCode(function ($id) use ($config, $disabled) { - $js = '$("#' . $id . '").datetimepicker(' . json_encode($config) . ');'; - if ($disabled) { - $js .= '$("#' . $id . ' input").prop(\'disabled\', true);'; - } - return $js; - }); + if ($component->isDisabled()) { + $tpl->setVariable("DISABLED", "disabled"); + } - $id = $this->bindJSandApplyId($component, $tpl); - return $this->wrapInFormContext($component, $tpl->get(), $id); + return $this->wrapInFormContext($component, $tpl->get(), $this->createId()); } protected function renderDurationField(F\Duration $component, RendererInterface $default_renderer): string @@ -689,16 +689,6 @@ protected function renderDurationField(F\Duration $component, RendererInterface $tpl = $this->getTemplate("tpl.duration.html", true, true); $this->applyName($component, $tpl); - /** - * @var $component F\Duration - */ - $component = $component->withAdditionalOnLoadCode( - function ($id) { - return "$(document).ready(function() { - il.UI.Input.duration.init('$id'); - });"; - } - ); $id = $this->bindJSandApplyId($component, $tpl); $input_html = ''; diff --git a/src/UI/examples/Input/Field/DateTime/base.php b/src/UI/examples/Input/Field/DateTime/base.php index 1d67f4b2ca38..81185ed65f74 100644 --- a/src/UI/examples/Input/Field/DateTime/base.php +++ b/src/UI/examples/Input/Field/DateTime/base.php @@ -21,8 +21,9 @@ function base() //Step 1: define the inputs $date = $ui->input()->field()->dateTime("Pick a date/time", "Pick any date you want. It will be shown in format YYYY-MM-DD"); + $date_now = new \DateTimeImmutable('now'); $formatted = $date - ->withMinValue(new \DateTimeImmutable()) + ->withMinValue($date_now) ->withFormat($data->dateFormat()->germanShort()) ->withLabel('future only') ->withByline('Only allows to pick a date in the future. It will be shown in format DD.MM.YYYY'); @@ -58,7 +59,7 @@ function base() ->withByline('Tokyo time+date is preset. Output is also Tokyo time.'); $disabled = $date - ->withValue($date_now->format($format)) + ->withValue($date_now->format($timezoned->getFormat()->toString())) ->withDisabled(true) ->withLabel('disabled') ->withByline('You cannot pick anything, as the field is disabled'); diff --git a/src/UI/templates/default/Input/tpl.datetime.html b/src/UI/templates/default/Input/tpl.datetime.html index 62b4665c771c..e1690a2c41d2 100644 --- a/src/UI/templates/default/Input/tpl.datetime.html +++ b/src/UI/templates/default/Input/tpl.datetime.html @@ -1,6 +1,5 @@
- value="{VALUE}" name="{NAME}" placeholder="{PLACEHOLDER}" class="form-control form-control-sm" /> - - {CALENDAR_GLYPH} - + type="{DTTYPE}" value="{VALUE}" name="{NAME}" + min="{MIN_DATE}" max="{MAX_DATE}" placeholder="{PLACEHOLDER}" + disabled="{DISABLED}" class="form-control form-control-sm" />
\ No newline at end of file diff --git a/src/UI/templates/js/Input/Field/duration.js b/src/UI/templates/js/Input/Field/duration.js deleted file mode 100644 index 88326d5d5e46..000000000000 --- a/src/UI/templates/js/Input/Field/duration.js +++ /dev/null @@ -1,36 +0,0 @@ -/** - * This links datetime-pickers together (for duration input) - * - * @author Nils Haagen - */ - -var il = il || {}; -il.UI = il.UI || {}; -il.UI.Input = il.UI.Input || {}; -(function ($, UI) { - - il.UI.Input.duration = (function ($) { - var init = function (id) { - var id = '#' + id, - inpts = $(id).find('.il-input-datetime'), - from = inpts[0], - until = inpts[1]; - - $(from).on("dp.change", function (e) { - $(until).data("DateTimePicker").minDate(e.date); - }); - $(until).on("dp.change", function (e) { - $(from).data("DateTimePicker").maxDate(e.date); - }); - }; - - return { - init: init - }; - - })($); -})($, il.UI.Input); - -$(document).on('dp.show', function(event) { - il.UI.page.fit($('.bootstrap-datetimepicker-widget')); -}); \ No newline at end of file diff --git a/tests/UI/Component/Input/Field/DateTimeInputTest.php b/tests/UI/Component/Input/Field/DateTimeInputTest.php index c80752160f03..dbbe9bcb9309 100644 --- a/tests/UI/Component/Input/Field/DateTimeInputTest.php +++ b/tests/UI/Component/Input/Field/DateTimeInputTest.php @@ -1,7 +1,5 @@ data_factory->dateFormat()->germanShort(); $datetime = $this->factory->datetime('label', 'byline') - ->withFormat($format); + ->withFormat($format); $this->assertEquals( $format, @@ -148,23 +148,6 @@ public function test_withInvalidTimeZone(): void $datetime->withTimeZone($tz); } - public function test_jsConfigRendering(): void - { - $datetime = $this->factory->datetime('label', 'byline'); - $js_binding = $this->getJavaScriptBinding(); - $this->getDefaultRenderer($js_binding)->render($datetime); - - $expected = '$("#id_1").datetimepicker({' - . '"showClear":true,' - . '"sideBySide":true,' - . '"format":"YYYY-MM-DD",' - . '"locale":"en"' - . '});'; - - $onload_js = array_shift($js_binding->on_load_code); - $this->assertEquals($expected, $onload_js); - } - public function test_withValueThatIsDateTimeImmutable(): void { $string_value = "1985-05-04"; diff --git a/tests/UI/Component/Input/Field/DurationInputTest.php b/tests/UI/Component/Input/Field/DurationInputTest.php index e756e2c35f61..7b351dc316e4 100644 --- a/tests/UI/Component/Input/Field/DurationInputTest.php +++ b/tests/UI/Component/Input/Field/DurationInputTest.php @@ -1,7 +1,5 @@
-
+
-
+
@@ -212,13 +212,13 @@ public function testRenderwithDifferentLabels($datetime): void
-
+
-
+