class JValidField { constructor(el) { this.Guid = el.dataset.guid; this.Index = parseInt(el.dataset.validIndex); this.Name = el.dataset.validName; this.OrgText = el.dataset.validOrgText; this.Text = el.dataset.validText; this.InputChar = parseInt(el.dataset.validInputChar); this.ShowStyle = parseInt(el.dataset.validShowStyle); this.ThousandFormat = el.dataset.validThousandFormat; } }; /* *画面(部品)単位のViewModel管理 *想定シナリオ *1.C# Blazor側でViewModelにViewModel生成、GuidやValidFieldをの属性にセットする *2.OnAfterRenderAsyncのfirstRenderでInputCoreのinit(Guid)を呼出し *3.InputCoreのinit(Guid)に、JViewModelを生成し、の属性よりValidFieldを生成し、入力制御を行う *4.C# Blazor側Page OR 部品 Dispose時に、InputCoreのdispose(Guid)を呼出し、廃棄する */ class JViewModel { constructor(guid) { this.Guid = guid this.Fields = []; this.FieldMap = new Map(); } add(field) { this.Fields.push(field); this.FieldMap.set(field.Name, field); } static create(guid) { return new JViewModel(guid); } }; /* * IMEモードなし状態: * 通常文字入力:keydown⇒keypress⇒input⇒keyup * Enter:keydown⇒keypress⇒change(※文字変更あった場合)⇒keyup * Tab:keydown⇒blur⇒focus(次)⇒keyup * ※その場合、入力文字毎制限はinputに行う * IMEモード状態:ひらがな * 通常文字入力:compositionstart⇒複数回keydown⇒input⇒keyup⇒compositionend * ※その場合、入力文字毎制限はcompositionendに行う * 全部入力内容のチェックタイミングはblurで行う * Up、End、Enterの判断はKeyUpの信頼度は一番高い、又Enterのみはkeypressでも可能です。 * * フォーカス移動、全部チェックのため、viewFieldsの配列が必要です。 */ class InputCore { constructor() { this.viewModelMap = new Map(); } static filter(e) { let index = parseInt(e.target.dataset.validIndex); let field = window.inputCore.viewModelMap.get(e.target.dataset.guid).Fields[index]; if (field.InputChar == 1) { return; } let v = e.target.value; // 全角数字変換 if ((field.InputChar & 0x02) == 0x02) { v = v.replace(/[0-9]/g, function (x) { return String.fromCharCode(x.charCodeAt(0) - 0xFEE0) }); } let limitChar = '[^'; if ((field.InputChar & 0x02) == 0x02) { limitChar += '0-9'; } //数字 if ((field.InputChar & 0x04) == 0x04) { limitChar += 'a-z'; } //小アルファベット if ((field.InputChar & 0x08) == 0x08) { limitChar += 'A-Z'; } //大アルファベット if ((field.InputChar & 0x10) == 0x10) { limitChar += 'ヲ-゚'; } //カナ if ((field.InputChar & 0x200) == 0x200) { limitChar += ' '; } // [space] if ((field.InputChar & 0x400) == 0x400) { limitChar += ':'; } // : if ((field.InputChar & 0x800) == 0x800) { limitChar += '-'; } // - if ((field.InputChar & 0x2000) == 0x2000) { limitChar += '.'; } // . if ((field.InputChar & 0x4000) == 0x4000) { limitChar += '/'; } // / if ((field.InputChar & 0x8000) == 0x8000) { limitChar += ','; } // , limitChar += ']'; var re = new RegExp(limitChar,'g'); v = v.replace(re, ''); //let v = e.target.value // .replace(/[0-9]/g, function (x) { return String.fromCharCode(x.charCodeAt(0) - 0xFEE0) }) // .replace(/[^0-9,.-]/g, ''); //.replace(/[0-9a-zA-Z]/g, function(x){ return String.fromCharCode(x.charCodeAt(0) - 0xFEE0) }) //.replace(/[^0-9a-zA-Z]/g, ''); //.replace(/[^0-9]/g, '') e.target.value = v; } dispose(guid) { try { viewModelMap.delete(guid); } catch(err) { console.log(err); } } init(guid) { let viewModel = new JViewModel(guid); let key = `[data-guid="${guid}"]`; var list = document.querySelectorAll(key); list.forEach(item => { let field = new JValidField(item); viewModel.add(field); }); this.viewModelMap.set(guid, viewModel); viewModel.Fields.forEach(item => { let id = `${guid}-${item.Index}`; var obj = document.getElementById(id); obj.addEventListener('focus', function (e) { console.log('focus', e.target.value, e.target.dataset.validName); let index = parseInt(e.target.dataset.validIndex); let field = window.inputCore.viewModelMap.get(e.target.dataset.guid).Fields[index]; field.OrgText = e.target.value; if (((field.ShowStyle & 0x04) == 0x04) && e.target.value.length > 0) { e.target.value = e.target.value.replace(",", ""); } DotNet.invokeMethodAsync('HotelPms.Client.Blazor', 'InputCoreEvent', { ID: e.target.dataset.guid, Index: index, Name: e.target.dataset.validName, EventName: "focus", Key: "", OrgText: field.OrgText, Text: e.target.value }) .then(data => { console.log(JSON.stringify(data)); }); }); obj.addEventListener('blur', function (e) { console.log('blur', e.target.value, e.target.dataset.validName); let index = parseInt(e.target.dataset.validIndex); var field = window.inputCore.viewModelMap.get(e.target.dataset.guid).Fields[index]; DotNet.invokeMethodAsync('HotelPms.Client.Blazor', 'InputCoreEvent', { ID: e.target.dataset.guid, Index: index, Name: e.target.dataset.validName, EventName: "blur", Key: "", OrgText: field.OrgText, Text: e.target.value }) .then(data => { console.log(JSON.stringify(data)); e.target.value = data.text; }); }); obj.addEventListener('keyup', function (e) { console.log('keyup', e.target.value, e.key, e.target.dataset.validName); if (e.key === "Enter" || e.key === "ArrowUp" || e.key === "End") { e.preventDefault(); e.stopPropagation(); let index = parseInt(e.target.dataset.validIndex); var field = window.inputCore.viewModelMap.get(e.target.dataset.guid).Fields[index]; DotNet.invokeMethodAsync('HotelPms.Client.Blazor', 'InputCoreEvent', { ID: e.target.dataset.guid, Index: index, Name: e.target.dataset.validName, EventName: "keyup", Key: e.key, OrgText: field.OrgText, Text: e.target.value }) .then(data => { console.log(JSON.stringify(data)); field.OrgText = data.orgText; e.target.value = data.text; if (data.nextFocus.length > 0) { let nextInput = document.getElementById(data.nextFocus); nextInput.focus(); nextInput.select(); } }); } }); obj.addEventListener('keypress', function (e) { console.log('keypress', e.target.value, e.key, e.target.dataset.validName); }); obj.addEventListener('keydown', function (e) { console.log('keydown', e.target.value, e.key, e.target.dataset.validName); }); obj.addEventListener('change', function (e) { console.log('change', e.target.value, e.key, e.target.dataset.validName); }); obj.addEventListener('input', function (e) { console.log('input', e.target.value, e.key, e.target.dataset.validName, e.isComposing); if (!e.isComposing) { InputCore.filter(e); } }); obj.addEventListener('compositionstart', function (e) { console.log('compositionstart', e.target.value, e.target.dataset.validName); }); obj.addEventListener('compositionend', function (e) { console.log('compositionend', e.target.value, e.target.dataset.validName); InputCore.filter(e); }); }); } }; window.inputCore = new InputCore();