Skip to content

Commit 409be03

Browse files
committed
fix(extensions): allow short mobile numbers and back-fill from dial string
The mobile number field drove a 342-entry international multimask whose country-code masks hijacked short digit input ("211..." -> "+211-..."), and the field's mask validation requires a completed mask, so 5/6/7-digit internal numbers could not be saved. - Add plain 7-digit formats (0##-####..9##-####) to InputMaskPatterns. - Partition the mask list so non-"+" (plain/national) masks are matched before per-country "+" masks. Short numbers (<=7 digits) now keep a plain format and complete; numbers longer than 7 digits or starting with "+" fall through to the full per-country international formatting. - Extract the mask setup into extension.initMobileMask() for reuse. - Back-fill an empty mobile number from a numeric dial string override on change, so the backend no longer drops the ExternalPhones row (and the dial string with it) when only the override was filled. Non-numeric dial strings are left untouched to avoid mangling them in the digit mask. Refs #1081
1 parent 2acc1a7 commit 409be03

4 files changed

Lines changed: 205 additions & 39 deletions

File tree

sites/admin-cabinet/assets/js/pbx/Extensions/extension-modify.js

Lines changed: 62 additions & 20 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

sites/admin-cabinet/assets/js/pbx/Extensions/input-mask-patterns.js

Lines changed: 71 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

sites/admin-cabinet/assets/js/src/Extensions/extension-modify.js

Lines changed: 61 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,7 @@ const extension = {
194194
extension.$number = $('#number');
195195
extension.$sip_secret = $('#sip_secret');
196196
extension.$mobile_number = $('#mobile_number');
197+
extension.$mobile_dialstring = $('#mobile_dialstring');
197198
extension.$fwd_forwarding = $('#fwd_forwarding');
198199
extension.$fwd_forwardingonbusy = $('#fwd_forwardingonbusy');
199200
extension.$fwd_forwardingonunavailable = $('#fwd_forwardingonunavailable');
@@ -476,26 +477,43 @@ const extension = {
476477
extension.cbOnCompleteNumber();
477478
});
478479

479-
// Set up the input masks for the mobile number input
480-
const maskList = $.masksSort(InputMaskPatterns, ['#'], /[0-9]|#/, 'mask');
481-
extension.$mobile_number.inputmasks({
482-
inputmask: {
483-
definitions: {
484-
'#': {
485-
validator: '[0-9]',
486-
cardinality: 1,
480+
// Set up the input masks for the mobile number input.
481+
//
482+
// The mask list is partitioned so that masks WITHOUT a leading "+" (plain national
483+
// and short-number formats) are matched before the per-country "+" masks. Combined
484+
// with the plain 7-digit formats in InputMaskPatterns, this lets short internal
485+
// numbers (5/6/7 digits) keep a plain format and complete/save instead of being
486+
// hijacked by a country-code mask (e.g. "+211-11-___-____") that never completes
487+
// and blocks the save (issue #1081 follow-up). Numbers longer than 7 digits, or any
488+
// value starting with "+", have no plain match left and fall through to the full
489+
// per-country international formatting automatically.
490+
const sortedMaskList = $.masksSort(InputMaskPatterns, ['#'], /[0-9]|#/, 'mask');
491+
const mobileMaskList = sortedMaskList
492+
.filter(item => item.mask.charAt(0) !== '+')
493+
.concat(sortedMaskList.filter(item => item.mask.charAt(0) === '+'));
494+
495+
// Reusable (re)initialiser so the dial-string auto-fill below can re-apply the mask
496+
// to a freshly injected raw value without it being truncated by the previous mask.
497+
extension.initMobileMask = function () {
498+
extension.$mobile_number.inputmasks({
499+
inputmask: {
500+
definitions: {
501+
'#': {
502+
validator: '[0-9]',
503+
cardinality: 1,
504+
},
487505
},
506+
oncleared: extension.cbOnClearedMobileNumber,
507+
oncomplete: extension.cbOnCompleteMobileNumber,
508+
showMaskOnHover: false,
488509
},
489-
oncleared: extension.cbOnClearedMobileNumber,
490-
oncomplete: extension.cbOnCompleteMobileNumber,
491-
showMaskOnHover: false,
492-
// Remove onBeforePaste to prevent conflicts with our custom handler
493-
},
494-
match: /[0-9]/,
495-
replace: '9',
496-
list: maskList,
497-
listKey: 'mask',
498-
});
510+
match: /[0-9]/,
511+
replace: '9',
512+
list: mobileMaskList,
513+
listKey: 'mask',
514+
});
515+
};
516+
extension.initMobileMask();
499517

500518
// Add handler for programmatic value changes (for tests and automation)
501519
const originalVal = $.fn.val;
@@ -597,6 +615,31 @@ const extension = {
597615
$(e.target).val('');
598616
}
599617
});
618+
619+
// When the dial string override is filled while the mobile number is still empty,
620+
// copy it into the (empty) mobile number and let the mask engage. Without a mobile
621+
// number the backend drops the whole ExternalPhones row on save, silently clearing
622+
// the dial string the user just typed (issue #1081 follow-up).
623+
extension.$mobile_dialstring.on('change', function () {
624+
const dialstring = (this.value || '').trim();
625+
const currentMobile = extension.$mobile_number.data('inputmask')
626+
? extension.$mobile_number.inputmask('unmaskedvalue')
627+
: (extension.$mobile_number.val() || '');
628+
// Only auto-fill from a plain phone-number dial string (optional leading "+").
629+
// A non-numeric dial string (e.g. "SIP/trunk/123") would be mangled by the
630+
// digit-only mask, so it is left untouched.
631+
if (/^\+?\d+$/.test(dialstring) && currentMobile === '') {
632+
// Remove the current mask, inject the raw value (so it is not truncated by a
633+
// shorter active mask), then re-initialise so the right mask is chosen and
634+
// formatting applied. 'change' keeps dependent handlers (availability) in sync.
635+
// NOTE: inputmasks('remove') nulls the `.inputmasks` method on the jQuery
636+
// object it is called on, so call it on a throwaway wrapper, not the cached one.
637+
$('#mobile_number').inputmasks('remove');
638+
extension.$mobile_number.val(dialstring);
639+
extension.initMobileMask();
640+
extension.$mobile_number.trigger('change');
641+
}
642+
});
600643
},
601644

602645

sites/admin-cabinet/assets/js/src/Extensions/input-mask-patterns.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,17 @@ const InputMaskPatterns = [
6868
{mask: '8##-###', cc: '', name_en: '', desc_en: '', name_ru: '', desc_ru: '',},
6969
{mask: '9##-###', cc: '', name_en: '', desc_en: '', name_ru: '', desc_ru: '',},
7070

71+
{mask: '0##-####', cc: '', name_en: '', desc_en: '', name_ru: '', desc_ru: '',},
72+
{mask: '1##-####', cc: '', name_en: '', desc_en: '', name_ru: '', desc_ru: '',},
73+
{mask: '2##-####', cc: '', name_en: '', desc_en: '', name_ru: '', desc_ru: '',},
74+
{mask: '3##-####', cc: '', name_en: '', desc_en: '', name_ru: '', desc_ru: '',},
75+
{mask: '4##-####', cc: '', name_en: '', desc_en: '', name_ru: '', desc_ru: '',},
76+
{mask: '5##-####', cc: '', name_en: '', desc_en: '', name_ru: '', desc_ru: '',},
77+
{mask: '6##-####', cc: '', name_en: '', desc_en: '', name_ru: '', desc_ru: '',},
78+
{mask: '7##-####', cc: '', name_en: '', desc_en: '', name_ru: '', desc_ru: '',},
79+
{mask: '8##-####', cc: '', name_en: '', desc_en: '', name_ru: '', desc_ru: '',},
80+
{mask: '9##-####', cc: '', name_en: '', desc_en: '', name_ru: '', desc_ru: '',},
81+
7182
{
7283
mask: '+8#(###)####-####', cc: 'AC', name_en: 'Ascension', desc_en: '', name_ru: 'Южная Корея', desc_ru: '',
7384
},

0 commit comments

Comments
 (0)