Adds a CSV Upload Button
// ==UserScript== // @name Work Search Record CSV Upload // @namespace https://brightentompkins.com // @version 0.1 // @description Adds a CSV Upload Button // @author vantaboard <[email protected]> // @match https://uio.edd.ca.gov/UIO/Pages/ExternalUser/Certification/FormCCA4581RegularDUAWorkSearchRecord.aspx // @icon https://www.google.com/s2/favicons?sz=64&domain=ca.gov // @license MIT // @grant none // ==/UserScript== function CSVToArray(strData, strDelimiter = ',') { const objPattern = new RegExp( `(\\${strDelimiter}|\\r?\\n|\\r|^)(?:"([^"]*(?:""[^"]*)*)"|([^"\\${strDelimiter}\\r\\n]*))`, 'gi' ); const arrData = [[]]; let arrMatches = null; while ((arrMatches = objPattern.exec(strData))) { const strMatchedDelimiter = arrMatches[1]; if ( strMatchedDelimiter.length && strMatchedDelimiter !== strDelimiter ) { arrData.push([]); } let strMatchedValue; if (arrMatches[2]) { strMatchedValue = arrMatches[2].replace(new RegExp('""', 'g'), '"'); } else { strMatchedValue = arrMatches[3]; } arrData[arrData.length - 1].push(strMatchedValue); } arrData.pop(); return arrData; } function getLabel(input) { let element = input; while (element) { if (element.tagName === 'LABEL') { return element.innerText; } if (element.querySelector('label')) { return [...element.querySelectorAll('label')].slice(-1)[0] .innerText; } element = element.parentElement; } } function fill(input, value) { console.log(`Setting ${getLabel(input).trim()} to ${value}`); input.value = value; input.dispatchEvent(new Event('change')); } function flatArray(...args) { const arr = []; args.forEach((arg) => { if (!arg) { return; } Array.isArray(arg) ? arr.push(...arg) : arr.push(arg); }); return arr; } function wrapInputId( token, suffix, prefix = [ 'contentMain', 'contentMain', 'ucRegularDUA4581WorkSearchRecordV2', 'frmFormWorkSearchInformation', ], postToken = 'ctl00', delimiter = '_' ) { return `#${flatArray(prefix, token, postToken, suffix).join(delimiter)}`; } const inputs = [ { regex: new RegExp(/date.+contact/i), formatter: (value) => new Intl.DateTimeFormat('en-US', { year: 'numeric', month: '2-digit', day: '2-digit', }).format(new Date(value)), suffix: 'txtDatePicker', token: 'prtDateOfContact', }, { regex: new RegExp(/type.+work|work.+type/i), suffix: 'txtValue', token: 'prtTypeOfWork', }, { regex: new RegExp(/employer.+agency|agency.+employer/i), suffix: 'txtValue', token: 'prtEmployerAgencyName', }, { regex: new RegExp(/contact.+type|type.+contact/i), formatter: (value) => ({ Mail: 6656, Fax: 6657, Email: 6658, 'In-Person': 6659, Online: 6660, Phone: 6661, }[String(value).trim()]), suffix: 'ddlValue', token: 'prtContactType', }, { regex: new RegExp(/outcome.+contact|contact.+outcome/i), formatter: (value) => ({ Applied: 6662, 'No Decision': 6663, Hired: 6664, 'Not Hiring': 6665, Pending: 6666, Interviewed: 6667, 'Interview Date Set': 6668, 'No response from employer': 6669, }[String(value).trim()]), suffix: 'ddlValue', token: 'prtOutcomeWorkInquiry', }, { regex: new RegExp(/person.+contacted|contacted.+person/i), suffix: 'txtValue', token: 'prtWorkSearchPersonContacted', }, { regex: new RegExp(/email|website|url/i), suffix: 'txtValue', token: 'prtWebSiteURLEmailContact', }, { regex: new RegExp(/phone|fax/i), suffix: 'txtValue', token: 'prtPhoneFaxNumber', }, { regex: new RegExp(/address.+1|1.+address/i), suffix: 'txtValue', token: 'prtAddress1', }, { regex: new RegExp(/address.+2|2.+address/i), suffix: 'txtValue', token: 'prtAddress2', }, { regex: new RegExp(/city/i), suffix: 'txtValue', token: 'prtCity', }, { regex: new RegExp(/state|province/i), suffix: 'txtValue', token: 'prtOtherState', }, { regex: new RegExp(/postal|zip/i), suffix: 'txtValue', token: 'prtPostalCode', }, { regex: new RegExp(/country/i), formatter: (value) => ({ Afghanistan: 329, Akrotiri: 377, Albania: 405, Algeria: 406, Andorra: 407, Angola: 450, Anguilla: 378, Antarctica: 341, 'Antigua and Barbuda': 283, Argentina: 360, Armenia: 408, Aruba: 478, 'Ashmore and Cartier Islands': 268, Australia: 361, Austria: 409, Azerbaijan: 342, 'Bahamas, The': 319, Bahrain: 410, Bangladesh: 343, Barbados: 379, 'Bassas da India': 297, Belarus: 411, Belgium: 412, Belize: 451, Benin: 479, Bermuda: 413, Bhutan: 452, Bolivia: 414, 'Bosnia and Herzegovina': 275, Botswana: 380, 'Bouvet Island': 311, Brazil: 453, 'British Indian Ocean Territory': 267, 'British Virgin Islands': 276, Brunei: 454, Bulgaria: 381, 'Burkina Faso': 320, Burma: 480, Burundi: 415, Cambodia: 382, Cameroon: 383, Canada: 448, 'Cape Verde': 344, 'Cayman Islands': 303, 'Central African Republic': 270, Chad: 505, Chile: 481, China: 482, 'Christmas Island': 291, 'Clipperton Island': 287, 'Cocos (Keeling) Islands': 273, Colombia: 384, Comoros: 416, 'Congo, Democratic Republic of the': 262, 'Congo, Republic of the': 277, 'Cook Islands': 321, 'Coral Sea Islands': 288, 'Costa Rica': 345, // eslint-disable-next-line quotes "Cote d'Ivoire": 312, Croatia: 417, Cuba: 506, Cyprus: 455, 'Czech Republic': 304, Denmark: 418, Dhekelia: 385, Djibouti: 386, Dominica: 387, 'Dominican Republic': 286, Ecuador: 419, Egypt: 483, 'El Salvador': 330, 'Equatorial Guinea': 289, Eritrea: 420, Estonia: 421, Ethiopia: 388, 'Europa Island': 313, 'Falkland Islands (Islas Malvinas)': 263, 'Faroe Islands': 314, Fiji: 507, Finland: 422, France: 456, 'French Guiana': 315, 'French Polynesia': 292, 'French Southern and Antarctic Lands': 261, Gabon: 484, 'Gambia, The': 331, 'Gaza Strip': 346, Georgia: 423, Germany: 424, Ghana: 485, Gibraltar: 362, 'Glorioso Islands': 293, Greece: 457, Greenland: 363, Grenada: 425, Guadeloupe: 347, Guam: 508, Guatemala: 364, Guernsey: 389, Guinea: 458, 'Guinea-Bissau': 316, Guyana: 459, Haiti: 486, 'Heard Island and McDonald Islands': 264, 'Holy See (Vatican City)': 274, Honduras: 390, 'Hong Kong': 365, Hungary: 426, Iceland: 427, India: 487, Indonesia: 366, Iran: 509, Iraq: 510, Ireland: 428, 'Isle of Man': 332, Israel: 460, Italy: 488, Jamaica: 429, 'Jan Mayen': 367, Japan: 489, Jersey: 461, Jordan: 462, 'Juan de Nova Island': 284, Kazakhstan: 348, Kenya: 490, Kiribati: 391, 'Korea, North': 322, 'Korea, South': 323, Kuwait: 463, Kyrgyzstan: 349, Laos: 511, Latvia: 464, Lebanon: 430, Lesotho: 431, Liberia: 432, Libya: 491, Liechtenstein: 317, Lithuania: 368, Luxembourg: 350, Macau: 492, Macedonia: 369, Madagascar: 351, Malawi: 465, Malaysia: 392, Maldives: 393, Mali: 512, Malta: 493, 'Marshall Islands': 294, Martinique: 352, Mauritania: 353, Mauritius: 370, Mayotte: 433, Mexico: 449, 'Micronesia, Federated States of': 266, Moldova: 434, Monaco: 466, Mongolia: 394, Montserrat: 354, Morocco: 435, Mozambique: 355, Namibia: 436, Nauru: 494, 'Navassa Island': 305, Nepal: 495, Netherlands: 333, 'Netherlands Antilles': 281, 'New Caledonia': 318, 'New Zealand': 334, Nicaragua: 371, Niger: 496, Nigeria: 437, Niue: 513, 'Norfolk Island': 306, 'Northern Mariana Islands': 271, Norway: 467, Oman: 514, Pakistan: 395, Palau: 497, Panama: 468, 'Papua New Guinea': 295, 'Paracel Islands': 298, Paraguay: 396, Peru: 515, Philippines: 335, 'Pitcairn Islands': 296, Poland: 469, Portugal: 397, 'Puerto Rico': 336, Qatar: 498, Reunion: 438, Romania: 439, Russia: 470, Rwanda: 471, 'S Georgia and S Sandwich Islands': 260, 'Saint Helena': 324, 'Saint Kitts and Nevis': 278, 'Saint Lucia': 337, 'Saint Pierre and Miquelon': 269, 'Saint Vincent and the Grenadines': 265, Samoa: 499, 'San Marino': 356, 'Sao Tome and Principe': 279, 'Saudi Arabia': 325, Senegal: 440, 'Serbia and Montenegro': 280, Seychelles: 357, 'Sierra Leone': 326, Singapore: 372, Slovakia: 398, Slovenia: 399, 'Solomon Islands': 299, Somalia: 441, 'South Africa': 327, Spain: 500, 'Spratly Islands': 300, 'Sri Lanka': 373, Sudan: 501, Suriname: 400, Svalbard: 401, Swaziland: 374, Sweden: 472, Switzerland: 338, Syria: 502, Taiwan: 473, Tajikistan: 358, Tanzania: 402, Thailand: 403, 'Timor-Leste': 339, Togo: 516, Tokelau: 442, Tonga: 503, 'Trinidad and Tobago': 285, 'Tromelin Island': 301, Tunisia: 443, Turkey: 474, Turkmenistan: 328, 'Turks and Caicos Islands': 272, Tuvalu: 475, Uganda: 476, Ukraine: 444, 'United Arab Emirates': 282, 'United Kingdom': 307, 'United States': 310, Uruguay: 445, Uzbekistan: 359, Vanuatu: 446, Venezuela: 375, Vietnam: 447, 'Virgin Islands': 308, 'Wake Island': 340, 'Wallis and Futuna': 290, 'West Bank': 376, 'Western Sahara': 309, Yemen: 504, Zambia: 477, Zimbabwe: 404, }[String(value).trim()]), suffix: 'ddlValue', token: 'prtCountry', }, ]; function inputByHeaders(headersArray) { const headers = headersArray.map((header) => { const input = inputs.find(({regex}) => regex.test(header)); if (!input) { return null; } return input; }, []); return headers; } const wrapWeekId = (token) => wrapInputId( token, '', [ 'contentMain', 'contentMain', 'ucFormCCA4581RegularDUACertificationWeeks', ], '' ); function load(data) { const {headers, rows} = data; headers.forEach((header) => { if (!header) { return; } const {token, suffix} = header; const element = document.querySelector(wrapInputId(token, suffix)); if (!element) { throw new Error(`Could not find element for ${token}`); } header.element = element; }); const row = rows[0]; headers.forEach((header, index) => { if (!header) { return; } const {element, formatter} = header; try { const value = formatter ? formatter(row[index]) : row[index]; fill(element, value); } catch (error) { if (error instanceof Error && error.name === 'RangeError') { console.warn( `Error filling ${getLabel(element) .toString() .trim()} with ${row[index]}` ); } throw error; } }); const additionalButton = document.querySelector( wrapInputId('prtISAdditionalWorkSerach', ['rblValue', '0']) ); const nextButton = document.querySelector( wrapInputId('btnNext', '', ['contentMain', 'contentMain'], '') ); additionalButton.click(); nextButton.click(); } const weekNumber = document.querySelector(wrapWeekId('lblWeekNumber')); const weekEnd = document.querySelector(wrapWeekId('lblWeekEndDate')); const weekHeader = weekEnd.parentElement; weekHeader.style.display = 'flex'; weekHeader.style.alignItems = 'center'; weekNumber.style.padding = '0 0.5rem'; const csvUploadInput = document.createElement('input'); csvUploadInput.style.display = 'none'; const csvUploadIcon = document.createElement('span'); csvUploadIcon.classList.add('ca-gov-icon-file-csv'); const csvUploadText = document.createElement('span'); csvUploadText.innerText = 'Upload CSV'; csvUploadText.style.fontSize = '1rem'; csvUploadText.style.userSelect = 'none'; csvUploadInput.type = 'file'; csvUploadInput.accept = '.csv'; csvUploadInput.addEventListener('change', (event) => { const file = event.target.files[0]; const reader = new FileReader(); reader.onload = (event) => { const csv = event.target.result; const csvArray = CSVToArray(csv); const [headers, ...rows] = csvArray; if (!rows.length) { return; } const inputHeaders = inputByHeaders(headers); window.localStorage.setItem('csvArray', JSON.stringify(csvArray)); const data = { headers: inputHeaders, rows, }; load(data); }; reader.readAsText(file); }); const csvUploadLabel = document.createElement('label'); csvUploadLabel.classList.add('nav-item'); csvUploadLabel.style.marginLeft = '5px'; csvUploadLabel.style.display = 'flex'; csvUploadLabel.style.alignItems = 'center'; csvUploadLabel.appendChild(csvUploadInput); csvUploadLabel.appendChild(csvUploadIcon); csvUploadLabel.appendChild(csvUploadText); weekHeader.appendChild(csvUploadLabel); const csvArray = JSON.parse(window.localStorage.getItem('csvArray')); if (csvArray) { const [headers, ...rows] = csvArray; rows.shift(); if (!rows.length) { window.localStorage.removeItem('csvArray'); } if (rows.length) { window.localStorage.setItem( 'csvArray', JSON.stringify([headers, ...rows]) ); const inputHeaders = inputByHeaders(headers); const data = { headers: inputHeaders, rows, }; load(data); } }