incremental_search
last update:
2020/12/19
required.js A
var COUNTRY_DATA = [ { japanese: "アイスランド", hiragane: "あいすらんど", english: "Iceland", number: "352", alpha3: "ISL", alpha2: "IS", area: "北ヨーロッパ", administrativeDivision: "ISO 3166-2:IS" }, { japanese: "アイルランド", hiragana: "あいるらんど", english: "Ireland", number: "372", alpha3: "IRL", alpha2: "IE", area: "西ヨーロッパ", administrativeDivision: "ISO 3166-2:IE" }, . . .
source A
<!doctype html> <html> <head> <meta charset="utf-8"> <title>plane</title> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1, maximum-scale=1"> <meta name="format-detection" content="telephone=no"> <link rel="stylesheet" href="https://3300.me/top/dest/sampleReset.css"> <style> body, div { padding: 10px; font-size: 12px; line-height: 1.8; background: #f1f1f1; } input { padding: 8px 6px 6px 8px; border: #fff 1px solid; } input::placeholder { color: #d1d1d1; } a { display: inline-block; color: #888; } </style> </head> <body> <div> <input type="text" value class="searchQuery" placeholder="Narrow down"> </div> <div> <p class="getNumber"></p> </div> <div> <ul class="searchResult"> </ul> </div> <script src="data/required.js"></script> <script> var data = COUNTRY_DATA; var query = d.querySelector('.searchQuery'); var result = d.querySelector('.searchResult'); var getNumber = d.querySelector('.getNumber'); var makeNumber = function (hit, total) { getNumber.innerHTML = hit + ' in ' + total; } var makeList = function (query) { var list = []; var total = 0; var hit = 0; Object.keys(data).forEach(function (key) { var target = data[key].english + ' / ' + data[key].japanese; var hiragana = data[key].hiragana; var reg = new RegExp(query, 'i'); total++; if (reg.test(target) || reg.test(hiragana)) { var li = d.createElement('li'); li.innerHTML = data[key].english + ' / '; var a = d.createElement('a'); a.setAttribute('href', 'https://www.google.com/search?q=' + data[key].japanese); a.innerHTML = data[key].japanese; li.appendChild(a); list.push(li); hit++; } makeNumber(hit, total); }); return list; }; var provideList = function (query) { result.innerHTML = ''; var list = makeList(query); Object.values(list).forEach(function (value) { result.appendChild(value); }); }; query.addEventListener('keyup', function (ev) { provideList(ev.target.value); }); // onload provideList(query.value); })(document); </script> </body> </html> code_popup
package.json
{ "name": "suggest sample", "version": "1.0.0", "description": "", "scripts": { "csvcat": "cat ./data/head.csv ./data/n*.csv > ./data/all.csv", "main": "node main", "m": "npm run csvcat && npm run main" }, "author": "", "license": "", "devDependencies": { "csvtojson": "^1.1.9", "moji": "^0.5.1" } } code_popup
main.js (converter: all.csv -> required.js)
var fs = require('fs'); var path = require('path'); var Converter = require("csvtojson").Converter; var converter = new Converter({}); var moji = require('moji'); // make json of all data converter.on("end_parsed", function (jsonArray) { fs.writeFile('./data/all.js', JSON.stringify(jsonArray, null, ' ')); }); fs.createReadStream("./data/all.csv").pipe(converter); // make json of require data var all = JSON.parse(fs.readFileSync('./data/all.js', 'utf8')); var target = './data/required.js'; var convert = function (kana) { return moji(kana).convert('HK', 'ZK').convert('KK', 'HG').toString(); }; var data = "var BANK_DATA = [\n"; for (var i = 0; i < all.length; i++) { if (i === 0 || all[i - 1].bank_kanji !== all[i].bank_kanji) { data += " {\n"; data += " name: '" + all[i].bank_kanji + "',\n"; data += " keywords: ['" + convert(all[i].bank_kana) + "', '" + all[i].bank_kanji+ "'],\n"; data += " branch: [\n"; } data += " {\n"; data += " name: '" + all[i].branch_kanji + "',\n"; data += " keywords: ['" + convert(all[i].branch_kana) + "', '" + all[i].branch_kanji + "']\n"; if (i === all.length - 1 || all[i].bank_kanji !== all[i + 1].bank_kanji) { data += " }\n"; } else { data += " },\n"; } if (i === all.length - 1 || all[i].bank_kanji !== all[i + 1].bank_kanji) { data += " ]\n"; if (i !== all.length - 1) { data += " },\n"; } else { data += " }\n"; } } } data += "];"; fs.appendFile(target, data); code_popup
all.csv (basic data)
"bank_no","branch_no","bank_kana","bank_kanji","branch_kana","branch_kanji","zipcode","address","phone_number","another_number","ex1","ex0" "0000","093","ニツポン","日本銀行","ホンテン","本店","103-8660","東京都中央区日本橋本石町2−1−1","03-3279-1111","1301","1","0" "0000","426","ニツポン","日本銀行","ヨコハマ","横浜支店","231-8710","神奈川県横浜市中区日本大通20−1","045-661-8111","1401","1","0" "0000","512","ニツポン","日本銀行","クシロ","釧路支店","085-0017","北海道釧路市幸町9−2","0154-24-8100","0106","1","0" . . .
required.js B
var BANK_DATA = [ { name: '日本銀行', keywords: ['につぽん', '日本銀行'], branch: [ { name: '本店', keywords: ['ほんてん', '本店'] }, { name: '横浜支店', keywords: ['よこはま', '横浜支店'] }, { name: '釧路支店', keywords: ['くしろ', '釧路支店'] }, . . .
source B
<!doctype html> <html> <head> <meta charset="utf-8"> <title>bankSuggest</title> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1, maximum-scale=1"> <meta name="format-detection" content="telephone=no"> <link rel="stylesheet" href="https://3300.me/top/dest/sampleReset.css"> <style> body { padding: 10px; line-height: 1.2; } h2 { padding-bottom: 4px; } p { padding-top: 6px; font-size: 12px; } label { font-size: 12px; } input[type=text] { padding: 6px; width: 100%; border: #ddd 1px solid; font-size: 14px; box-sizing: border-box; border-radius: 0; -webkit-appearance: none; outline: 0; } input[type=text]:focus { outline: 0; } .formItem { padding-bottom: 20px; } .confirmBtn button { padding: 10px 30px; font-size: 15px; background: #fff; border: #000 1px solid; cursor: pointer; vertical-align: top; } .bankNameArea button { padding: 10px 30px; font-size: 15px; background: #fff; border: #000 1px solid; cursor: pointer; vertical-align: top; } .viewValue { display: inline-block; width: calc(100% - 108px); margin-top: 12px; padding-left: 10px; font-size: 18px; vertical-align: top; } .overlay { display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: #000; opacity: 0.3; } .popupCommon { position: absolute; top: 0; left: 50%; -webkit-transform: translate(-50%, 0); -ms-transform: translate(-50%, 0); transform: translate(-50%, 0); width: 800px; padding: 15px; border: #000 1px solid; background: #fff; font-size: 13px; box-sizing: border-box; } .popupCommon h3 { font-size: 15px; font-weight: bold; margin-bottom: 6px; } .popupCommon table { width: 100%; border-top: #999 1px solid; border-bottom: #999 1px solid; } .popupBank { display: none; } .popupBranch { display: none; } .popupBranch tr + tr { border-top: #ccc 1px solid; } .popupCommon th, .popupCommon td { padding: 10px; } .popupCommon th { width: 100px; background: #f1f1f1; } .popupCommon td { position: relative; } .popupCommon input[type=text] { border: #ddd 1px solid; } .majorBank { margin-top: 19px; } .majorBank li { display: inline-block; width: 244px; margin-top: 10px; } .majorBank a { display: inline-block; color: #333; } .itemTable01, .itemTable02 { margin-top: 20px; } .rewriteBank { margin: 2px 2px 4px; padding: 5px 8px 4px 7px; font-size: 13px; color: #000; border: #000 1px solid; background: #fff; cursor: pointer; } .alertBank, .alertBranch { display: none; color: #f00; } .suggestBank, .suggestBranch { display: none; position: absolute; top: 44px; left: 10px; width: calc(100% - 20px); margin-bottom: 20px; padding: 5px 0; border: #ddd 1px solid; background: #fff; } .suggestBank li, .suggestBranch li { display: inline-block; margin: 2px; } .suggestBank a, .suggestBranch a { display: block; padding: 5px 10px; color: #333; } .confirmBank, .confirmBranch { display: inline-block; margin: 20px auto 6px; padding: 10px 20px; border: #000 1px solid; font-size: 14px; color: #000; cursor: pointer; text-decoration: none; } .closePopup { position: absolute; top: 0; right: 0; display: block; width: 44px; height: 44px; } .closePopup:before { position: relative; top: 4px; left: 24px; content: ""; display: block; width: 2px; height: 32px; background: #000; -webkit-transform: rotate(45deg); -ms-transform: rotate(45deg); transform: rotate(45deg); } .closePopup:after { position: relative; top: -28px; left: 24px; content: ""; display: block; width: 2px; height: 32px; background: #000; -webkit-transform: rotate(-45deg); -ms-transform: rotate(-45deg); transform: rotate(-45deg); } .sp .viewValue { width: calc(100% - 102px); margin-top: 15px; padding-left: 5px; font-size: 15px; } .sp .popupCommon { width: calc(100% - 30px); } .sp .popupCommon th { width: 88px; } .sp .popupCommon td { padding: 7px 6px; } .sp .majorBank { margin-top: 4px; } .sp .majorBank li { width: 150px; margin-top: 8px; } .sp .itemTable01, .sp .itemTable02 { margin-top: 10px; } .sp .suggestBank, .sp .suggestBranch { top: 41px; left: 6px; width: calc(100% - 12px); } .sp .suggestBank a, .sp .suggestBranch a { font-size: 13px; } .sp .confirmBank, .sp .confirmBranch { margin: 8px auto 0; } </style> </head> <body> <div class="formArea"> <form action="#" method="post"> <div class="bankNameArea"> <div class="formItem"> <h2>金融機関名 <span class="requisite">※</span></h2> <button class="bankSearch">検索</button> <span class="viewValue"></span> <input type="hidden" class="hiddenValue" name="bankname" data-label="金融機関名" value=""> <p>「検索」ボタンから金融機関名を設定してください。<br> ※金融機関名選択のメニューは日本語のみの表記になります。<br> ※ゆうちょ銀行の方は支店名と口座番号を<a href="http://www.jp-bank.japanpost.jp/kojin/sokin/furikomi/kj_sk_fm_furikomi.html" target="_blank">こちら</a>で確認してください。</p> </div> <!--/bankNameArea--></div> <div class="formItem"> <h2>預金種目 <span class="requisite">※</span></h2> <div data-rule="checked" data-label="預金種目"> <label><input type="radio" name="banktype" value="普通">普通</label> <label><input type="radio" name="banktype" value="当座">当座</label> </div> </div> <div class="formItem"> <h2>口座番号 <span class="requisite">※</span></h2> <input type="text" pattern="\d{7}" name="banknumber" data-label="口座番号" required="required" value=""> <p>例) 9999999<br> ※半角数字7文字に満たない場合は、最初に0をつけてください。</p> </div> <div class="formItem"> <h2>口座名義 <span class="requisite">※</span></h2> <input type="text" name="bankusername" data-label="口座名義" required="required" maxlength="200"> <p>例)ヤマダ タロウ<br> ※氏名と口座の名義は、一致している必要があります。<br> ※口座名義は金融機関に登録した全角カタカナ・全角英数字で入力してください。<br> ※姓と名の間にスペースを入力してください。<br> ※小文字は大文字に変換して登録します。「ョ」→「ヨ」、「ー(長音)」は「‐(ハイフン)」に変換されます。<br> ※口座名義で使用できる文字や略称については<a href="http://www.smbc.co.jp/direct/help_furikomi/14.html" target="_blank">こちら</a>を確認してください。</p> </div> <div class="confirmArea"> <div class="confirmBtn"><button type="submit">送信</button></div> </div> </form> <!--formArea--></div> <div class="overlay"></div> <div class="popupBank popupCommon"> <h3>金融機関名の選択</h3> <p>下記以外の銀行の場合は金融機関名を入力してください。</p> <ul class="majorBank"> <li><a href="#">三菱UFJ銀行</a></li> <li><a href="#">りそな銀行</a></li> <li><a href="#">ジャパンネット銀行</a></li> <li><a href="#">三井住友銀行</a></li> <li><a href="#">埼玉りそな銀行</a></li> <li><a href="#">楽天銀行</a></li> <li><a href="#">みずほ銀行</a></li> <li><a href="#">ゆうちょ銀行</a></li> </ul> <table class="itemTable01"> <tr> <th>金融機関名</th> <td> <input type="text" value="" class="inputBank"> <p class="alertBank">金融機関名を選択してください</p> <ul class="suggestBank"> </ul> </td> </tr> </table> <a href="#" class="confirmBank">決定</a> <a href="#" class="closePopup"></a> <!--/popupBank--></div> <div class="popupBranch popupCommon"> <h3>支店名の選択</h3> <table class="itemTable02"> <tr> <th>金融機関名</th> <td> <span class="bankName"></span> <button class="rewriteBank">変更</button> </td> </tr> <tr> <th>支店名</th> <td> <input type="text" value="" class="inputBranch"> <p class="alertBranch">支店名を選択してください</p> <ul class="suggestBranch"> </ul> </td> </tr> </table> <a href="#" class="confirmBranch">決定</a> <a href="#" class="closePopup"></a> <!--/popupBranch--></div> <script src="BANK_DATA/data/required.js"></script> <script> (function (w) { var ua = w.navigator.userAgent; // sp if (/iPhone/.test(ua) || /iPod/.test(ua)) { w.deviceType = 'sp'; } else if (/Android/.test(ua) && /Mobile/.test(ua)) { w.deviceType = 'sp'; } else if (/Windows/.test(ua) && /Phone/.test(ua)) { w.deviceType = 'sp'; } else if (/Firefox/.test(ua) && /Mobile/.test(ua)) { w.deviceType = 'sp'; } else if (/BlackBerry/.test(ua) || /BB10/.test(ua)) { w.deviceType = 'sp'; } else if (/Nokia/.test(ua)) { w.deviceType = 'sp'; // tablet } else if (/iPad/.test(ua)) { w.deviceType = 'tablet'; } else if (/Android/.test(ua) && !(/Mobile/.test(ua))) { w.deviceType = 'tablet'; } else if (/Windows/.test(ua) && /Touch/.test(ua) && !(/Tablet PC/.test(ua))) { w.deviceType = 'tablet'; } else if (/Firefox/.test(ua) && /Tablet/.test(ua)) { w.deviceType = 'tablet'; } else if (/Playbook/.test(ua)) { w.deviceType = 'tablet'; } else if (/Kindle/.test(ua) || /Silk/.test(ua)) { w.deviceType = 'tablet'; // pc } else { w.deviceType = 'pc'; } w.isMS = w.deviceType === 'pc' && /Windows NT/.test(ua) && (!(/Chrome/.test(ua) || /Firefox/.test(ua))) ? true : false; // ie or edge w.isPC = w.deviceType === 'pc' ? true : false; w.isSP = w.deviceType === 'sp' ? true : false; w.isTABLET = w.deviceType === 'tablet' ? true : false; })(window); (function (w, doc) { if (w.isSP) { var html = doc.querySelector('html'); html.setAttribute('class', 'sp'); } var overlay = doc.querySelector('.overlay'); var popupBank = doc.querySelector('.popupBank'); var popupBranch = doc.querySelector('.popupBranch'); var alertBank = doc.querySelector('.alertBank'); var alertBranch = doc.querySelector('.alertBranch'); var suggestBank = doc.querySelector('.suggestBank'); var suggestBranch = doc.querySelector('.suggestBranch'); var inputBank = doc.querySelectorAll('.inputBank'); var inputBranch = doc.querySelectorAll('.inputBranch'); var bankName = doc.querySelector('.bankName'); var viewValue = doc.querySelector('.viewValue'); var hiddenValue = doc.querySelector('.hiddenValue'); var bankSearch = doc.querySelector('.bankSearch'); var closePopup = doc.querySelectorAll('.closePopup'); var majorBankA = doc.querySelectorAll('.majorBank a'); var rewriteBank = doc.querySelector('.rewriteBank'); var confirmBank = doc.querySelector('.confirmBank'); var confirmBranch = doc.querySelector('.confirmBranch'); var submitButton = doc.querySelector('button[type=submit]'); var maxItemLength = undefined; // ex 20 var branchName; var recScrollTop; bankSearch.addEventListener('click', function (e) { overlay.style.display = 'block'; popupBank.style.display = 'block'; popupBranch.style.display = 'block'; var windowVerticalCenter = (w.innerHeight / 2); var popupBankHeight = popupBank.offsetHeight; var popupBranchHeight = popupBranch.offsetHeight; var posLayerBank = windowVerticalCenter - (popupBankHeight / 2); var posLayerBranch = windowVerticalCenter - (popupBranchHeight / 2); popupBank.style.top = posLayerBank + 'px'; popupBranch.style.top = posLayerBranch + 'px'; popupBranch.style.display = 'none'; e.preventDefault(); }, false); closePopup.forEach(function (el) { el.addEventListener('click', function (e) { overlay.style.display = 'none'; popupBank.style.display = 'none'; popupBranch.style.display = 'none'; alertBank.style.display = 'none'; alertBranch.style.display = 'none'; suggestBank.style.display = 'none'; suggestBranch.style.display = 'none'; inputBank[0].value = ""; inputBranch[0].value = ""; e.preventDefault(); }); }); majorBankA.forEach(function (el) { el.addEventListener('click', function (e) { inputBank[0].value = e.target.text; alertBank.style.display = 'none'; suggestBank.style.display = 'none'; e.preventDefault(); }); }); var searchData = function (data, e) { var value = e.target.value; var searchRE = new RegExp('^.*' + value + '.*$', 'i'); var result = []; data.forEach(function (target) { var word = target.keywords.filter(function (keyword) { return keyword.match(searchRE); }); if (word.length > 0) { result.push(target.name); } }); return result; }; var makeSuggest = function (sheet, e, result) { if (result[0] && e.target.value !== '') { sheet.style.display = 'block'; } else { sheet.style.display = 'none'; } for (i = 0; i < result.length; i++) { var li = doc.createElement('li'); var a = doc.createElement('a'); a.setAttribute('href', '#'); a.innerHTML = result[i]; li.appendChild(a); sheet.appendChild(li); if (i === maxItemLength) { break; } }; }; [inputBank, inputBranch].forEach(function (el) { el[0].addEventListener('keyup', function (e) { var isBank = el[0].className === 'inputBank'; var suggest = isBank ? doc.querySelector('.suggestBank') : doc.querySelector('.suggestBranch'); var targetName = el[0].innerHTML; suggest.innerHTML = ''; if (isBank) { var data = BANK_DATA; } else { targetName = doc.querySelector('.bankName').innerText; for (i = 0; i < BANK_DATA.length; i++) { if (targetName === BANK_DATA[i].name) { var data = BANK_DATA[i].branch; break; } } } var result = searchData(data, e); makeSuggest(suggest, e, result); var items = suggest.getElementsByTagName('a'); Object.values(items).forEach(function (value) { value.addEventListener('click', function (item) { e.target.value = item.target.innerText; suggest.style.display = ''; w.scrollTop = recScrollTop; }); }); e.preventDefault(); }); }); rewriteBank.addEventListener('click', function () { popupBank.style.display = 'block'; popupBranch.style.display = 'none'; alertBank.style.display = 'none'; alertBranch.style.display = 'none'; suggestBank.style.display = 'none'; suggestBranch.style.display = 'none'; inputBank[0].value = ""; inputBranch[0].value = ""; }); var viewValue = doc.querySelector('.viewValue'); var hiddenValue = doc.querySelector('.hiddenValue'); var confirmNames = function (bankName, branchName) { viewValue.innerHTML = bankName + ' ' + branchName; hiddenValue.value = bankName + ' ' + branchName; } confirmBank.addEventListener('click', function (e) { var value = doc.querySelector('.inputBank').value; var bankNameArr = []; BANK_DATA.forEach(function (bank) { bankNameArr.push(bank.name); }); if (bankNameArr.indexOf(value) >= 0) { bankName = doc.querySelector('.bankName'); popupBank.style.display = 'none'; alertBank.style.display = 'none'; popupBranch.style.display = 'block'; bankName.innerHTML = value; } else { alertBank.style.display = 'block'; suggestBank.style.display = 'none'; } e.preventDefault(); }); confirmBranch.addEventListener('click', function (e) { bankName = doc.querySelector('.bankName').innerText; branchName = doc.querySelector('.inputBranch').value; var branchNameArr = []; for (i = 0; i < BANK_DATA.length; i++) { if (bankName === BANK_DATA[i].name) { BANK_DATA[i].branch.forEach(function (branch) { branchNameArr.push(branch.name); }); break; } } if (branchNameArr.indexOf(branchName) >= 0) { popupBranch.style.display = 'none'; alertBranch.style.display = 'none'; overlay.style.display = 'none'; confirmNames(bankName, branchName); } else { alertBranch.style.display = 'block'; suggestBranch.style.display = 'none'; } e.preventDefault(); }); submitButton.addEventListener('click', function (e) { // alert bank number var value = doc.querySelector('input[name=banknumber]').value; if (value && value.length !== 7) { alert('口座番号は半角数字7文字で入力してください'); e.preventDefault(); } // replace characters var username = doc.querySelector('input[name=bankusername]').value; var correspond = { 'ァ': 'ア', 'ィ': 'イ', 'ゥ': 'ウ', 'ェ': 'エ', 'ォ': 'オ', 'ッ': 'ツ', 'ャ': 'ヤ', 'ュ': 'ユ', 'ョ': 'ヨ', 'ー': '-', }; Object.entries(correspond).forEach(function (entry) { var multipleEntry = new RegExp(entry[0], 'g'); username = username.replace(multipleEntry, entry[1]); }); username = username.toUpperCase(); doc.querySelector('[name=bankusername]').value = username; e.preventDefault(); }); // for stop submit by enter key var form = doc.getElementsByTagName('form'); form[0].addEventListener('keypress', function (e) { if ((e.which && e.which === 13) || (e.keyCode && e.keyCode === 13)) { return false; } else { return true; } }); // for confirm data after history back if (inputBank.value !== undefined) { confirmNames(inputBank.value, inputBranch.value); } })(window, document); </script> </body> </html> code_popup