您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Auto-fill job application forms on WorkDay by first adding all sections, then filling them.
// ==UserScript== // @name Job Application Auto-Filler - WorkDay // @namespace https://greasyfork.org/en/users/670188-hacker09?sort=daily_installs // @version 2 // @description Auto-fill job application forms on WorkDay by first adding all sections, then filling them. // @author hacker09 // @icon https://i.imgur.com/3R9QyLR.png // @match https://*.myworkday.com/* // @grant none // ==/UserScript== (function() { 'use strict'; //Configuration - Your actual data. const formData = { jobs: [ { //Newest job first title: "Senior Software Developer", company: "Tech Solutions Inc.", location: "San Francisco", startMonth: "01", startYear: "2022", currentlyWork: true, //Set to 'true' for a current job endMonth: "", //Leave empty if currently working here endYear: "", //Leave empty if currently working here summary: "• Led a team of 5 developers in creating a new e-commerce platform.\n\n• Wrote high-quality, scalable code using React and Node.js.\n\n• Optimized application performance, resulting in a 30% reduction in load times." }, { //Older job title: "IT Support Intern", company: "Global Innovations LLC.", location: "New York", startMonth: "06", startYear: "2021", currentlyWork: false, endMonth: "12", endYear: "2021", summary: "• Provided technical assistance to over 200 employees.\n\n• Managed user accounts and system permissions.\n\n• Documented and resolved IT support tickets efficiently." } ], education: [ { //Most recent education first schoolName: "State University", degree: "BS", //Use abbreviations like BS, MS, PhD, or GED fieldOfStudy: "Computer Science", startYear: "2018", endYear: "2022" }, { //Older education schoolName: "Community College", degree: "GED", fieldOfStudy: "Information Technology", startYear: "2016", endYear: "2018" } ], skills: "JavaScript, React, Node.js, HTML, CSS, SQL, Python, Project Management, Team Leadership, Agile Methodologies, AWS, Docker", languages: [ { name: "English", isNative: true, //Set to 'true' for a native language listeningproficiency: "5 - Native or Bilingual Proficiency", readingproficiency: "5 - Native or Bilingual Proficiency", speakingproficiency: "5 - Native or Bilingual Proficiency", writingproficiency: "5 - Native or Bilingual Proficiency" }, { name: "Spanish", isNative: false, listeningproficiency: "3 - Professional Working Proficiency", readingproficiency: "3 - Professional Working Proficiency", speakingproficiency: "2 - Limited Working Proficiency", writingproficiency: "2 - Limited Working Proficiency" } ] }; const buttonId = 'workday-autofill-btn'; //Unique ID for the button function delay(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } async function fillInputField(element, value) { if (!element) return; element.focus(); await delay(100); element.value = value; element.dispatchEvent(new Event('input', { bubbles: true })); element.dispatchEvent(new Event('change', { bubbles: true })); element.blur(); await delay(100); } async function fillDegreeField(element, value) { if (!element) return; element.focus(); element.select(); element.click(); //Click to open dropdown await delay(500); //Type value to filter options element.value = ''; for (let char of value) { element.value += char; element.dispatchEvent(new KeyboardEvent('keydown', { key: char, bubbles: true })); element.dispatchEvent(new KeyboardEvent('keypress', { key: char, bubbles: true })); element.dispatchEvent(new Event('input', { bubbles: true })); element.dispatchEvent(new KeyboardEvent('keyup', { key: char, bubbles: true })); await delay(100); } //Press Enter to filter/search element.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', code: 'Enter', bubbles: true })); element.dispatchEvent(new KeyboardEvent('keyup', { key: 'Enter', code: 'Enter', bubbles: true })); await delay(1000); //Find and click matching option - FIXED: exclude already selected items const dropdownOptions = document.querySelectorAll('[data-automation-id="promptOption"]'); for (const option of dropdownOptions) { const optionText = (option.textContent || option.dataset.automationLabel || '').trim(); //Skip if this is a selected item (pill) const parentContainer = option.closest('[data-automation-id="selectedItem"]'); if (parentContainer) { continue; } if (optionText === value || optionText.toLowerCase() === value.toLowerCase()) { const clickTarget = option.closest('[role="option"]') || option.parentElement.closest('[role="option"]') || option; //Try clicking the radio button inside const radioBtn = clickTarget.querySelector('input[type="radio"]') || clickTarget.querySelector('[data-automation-id="radioBtn"]'); if (radioBtn) { radioBtn.click(); radioBtn.dispatchEvent(new Event('change', { bubbles: true })); } else { clickTarget.click(); } await delay(500); return; } } } async function fillDateFields(monthElement, yearElement, month, year) { if (monthElement && month) { monthElement.click(); monthElement.focus(); await delay(100); monthElement.select(); monthElement.value = ''; for (let char of month) { monthElement.value += char; monthElement.dispatchEvent(new KeyboardEvent('keydown', { key: char, code: `Digit${char}`, bubbles: true })); monthElement.dispatchEvent(new KeyboardEvent('keypress', { key: char, code: `Digit${char}`, bubbles: true })); monthElement.dispatchEvent(new Event('input', { bubbles: true })); monthElement.dispatchEvent(new KeyboardEvent('keyup', { key: char, code: `Digit${char}`, bubbles: true })); await delay(100); } monthElement.dispatchEvent(new Event('change', { bubbles: true })); await delay(100); } if (yearElement && year) { yearElement.click(); yearElement.focus(); await delay(100); yearElement.select(); yearElement.value = ''; for (let char of year) { yearElement.value += char; yearElement.dispatchEvent(new KeyboardEvent('keydown', { key: char, code: `Digit${char}`, bubbles: true })); yearElement.dispatchEvent(new KeyboardEvent('keypress', { key: char, code: `Digit${char}`, bubbles: true })); yearElement.dispatchEvent(new Event('input', { bubbles: true })); yearElement.dispatchEvent(new KeyboardEvent('keyup', { key: char, code: `Digit${char}`, bubbles: true })); await delay(100); } yearElement.dispatchEvent(new Event('change', { bubbles: true })); yearElement.dispatchEvent(new KeyboardEvent('keydown', { key: 'Tab', code: 'Tab', bubbles: true })); await delay(100); } } async function selectDropdownOption(triggerElement, valueToSelect) { if (!triggerElement || !valueToSelect) return; triggerElement.click(); await delay(1000); //Increased delay const options = document.querySelectorAll('[data-automation-id="promptOption"]'); for (const option of options) { const optionText = (option.textContent || option.dataset.automationLabel || '').trim(); if (optionText.toLowerCase() === valueToSelect.toLowerCase()) { option.closest('[role="option"]')?.click(); await delay(500); return; } } document.body.click(); //Click away to close dropdown if no match found await delay(200); } //NEW FUNCTION: Clicks all "Add" buttons first async function addSections() { const addBtns = document.querySelectorAll('[data-automation-id="panelSetAddButton"]'); if (addBtns.length === 0) return; //Add job sections (assumes 1 is already visible) for (let i = 1; i < formData.jobs.length; i++) { addBtns[0]?.click(); //Assumes first add button is for jobs await delay(1500); } //Add education sections (assumes 1 is already visible) for (let i = 1; i < formData.education.length; i++) { addBtns[1]?.click(); //Assumes second add button is for education await delay(1500); } //Add language sections (assumes it starts with 0) const lastAddBtn = addBtns[addBtns.length - 1]; for (let i = 0; i < formData.languages.length; i++) { lastAddBtn?.click(); //Assumes last add button is for languages await delay(1500); } } //MODIFIED: Removed "Add" button logic async function fillJobSection() { for (let i = 0; i < formData.jobs.length; i++) { const job = formData.jobs[i]; const titleInputs = document.querySelectorAll('input[id*="jobHistoryTitle"]'); await fillInputField(titleInputs[i], job.title); const companyInputs = document.querySelectorAll('input[id*="jobHistoryCompany"]'); await fillInputField(companyInputs[i], job.company); const locationInputs = document.querySelectorAll('input[id*="jobHistoryLocation"]'); await fillInputField(locationInputs[i], job.location); const allMonthInputs = document.querySelectorAll('input[id*="dateSectionMonth"]'); const allYearInputs = document.querySelectorAll('input[id*="dateSectionYear"]'); await fillDateFields(allMonthInputs[i * 2], allYearInputs[i * 2], job.startMonth, job.startYear); const currentlyWorkInputs = document.querySelectorAll('input[id*="currentlyWorkHere"]'); if (currentlyWorkInputs[i] && job.currentlyWork) { if (!currentlyWorkInputs[i].checked) currentlyWorkInputs[i].click(); } if (!job.currentlyWork) { await fillDateFields(allMonthInputs[i * 2 + 1], allYearInputs[i * 2 + 1], job.endMonth, job.endYear); } const summaryTextareas = document.querySelectorAll('textarea[id*="jobSummary"]'); await fillInputField(summaryTextareas[i], job.summary); } } //MODIFIED: Removed "Add" button logic async function fillEducationSection() { for (let i = 0; i < formData.education.length; i++) { const edu = formData.education[i]; const schoolInputs = document.querySelectorAll('input[id*="schoolName"]'); await fillInputField(schoolInputs[i], edu.schoolName); const degreeInputs = document.querySelectorAll('input[id*="schoolDegrees"]'); await fillDegreeField(degreeInputs[i], edu.degree); await delay(1500); const fieldInputs = document.querySelectorAll('input[id*="fieldOfStudy"]'); await fillInputField(fieldInputs[i], edu.fieldOfStudy); const allYearInputs = document.querySelectorAll('input[id*="dateSectionYear"]'); const jobYearFieldsCount = document.querySelectorAll('input[id*="jobHistoryTitle"]').length * 2; const eduStartYearIndex = jobYearFieldsCount + (i * 2); const eduEndYearIndex = jobYearFieldsCount + (i * 2) + 1; await fillDateFields(null, allYearInputs[eduStartYearIndex], '', edu.startYear); await fillDateFields(null, allYearInputs[eduEndYearIndex], '', edu.endYear); } } async function fillSkillsSection() { const skillsTextarea = document.querySelector('textarea[id*="skills"]'); await fillInputField(skillsTextarea, formData.skills); } //MODIFIED: Removed "Add" button logic and added proficiency filling async function fillLanguagesSection() { for (let i = 0; i < formData.languages.length; i++) { const lang = formData.languages[i]; //Select language name const langSelectWidgets = document.querySelectorAll('[data-automation-id="selectWidget"][id*="languages"]'); await selectDropdownOption(langSelectWidgets[i], lang.name); //Check "native language" if applicable const nativeCheckboxes = document.querySelectorAll('input[id*="myNativeLanguage"]'); if (nativeCheckboxes[i] && lang.isNative && !nativeCheckboxes[i].checked) { nativeCheckboxes[i].click(); } //Select proficiency levels const allProficiencyTriggers = document.querySelectorAll('[data-automation-id="selectWidget"][id*="langProficiencies"]'); const proficiencyTriggersForCurrentLang = Array.from(allProficiencyTriggers).slice(i * 4, i * 4 + 4); if (proficiencyTriggersForCurrentLang.length >= 4) { await selectDropdownOption(proficiencyTriggersForCurrentLang[0], lang.listeningproficiency); await selectDropdownOption(proficiencyTriggersForCurrentLang[1], lang.readingproficiency); await selectDropdownOption(proficiencyTriggersForCurrentLang[2], lang.speakingproficiency); await selectDropdownOption(proficiencyTriggersForCurrentLang[3], lang.writingproficiency); } } } //NEW main function to orchestrate adding and then filling async function runAutoFiller() { const triggerBtn = document.getElementById(buttonId); if (!triggerBtn) return; console.log("Starting form auto-fill..."); triggerBtn.disabled = true; triggerBtn.textContent = 'Filling...'; console.log("Phase 1: Adding all necessary sections."); await addSections(); await delay(1000); //Wait for DOM to update console.log("Phase 2: Populating data into sections."); await fillJobSection(); await fillEducationSection(); await fillSkillsSection(); await fillLanguagesSection(); triggerBtn.disabled = false; triggerBtn.textContent = 'Auto-Fill Form'; console.log("Form auto-fill completed!"); } function handlePageChange() { const onApplyPage = location.pathname.includes('/apply/'); const buttonExists = document.getElementById(buttonId); if (onApplyPage && !buttonExists) { //Create and append the button if on the apply page and it doesn't exist const triggerBtn = document.createElement('button'); triggerBtn.id = buttonId; triggerBtn.textContent = 'Auto-Fill Form'; triggerBtn.style.position = 'fixed'; triggerBtn.style.top = '10px'; triggerBtn.style.right = '10px'; triggerBtn.style.zIndex = '9999'; triggerBtn.style.backgroundColor = '#007bff'; triggerBtn.style.color = 'white'; triggerBtn.style.border = 'none'; triggerBtn.style.padding = '10px'; triggerBtn.style.borderRadius = '5px'; triggerBtn.style.cursor = 'pointer'; triggerBtn.onclick = runAutoFiller; document.body.appendChild(triggerBtn); } else if (!onApplyPage && buttonExists) { //Remove the button if not on the apply page and it exists buttonExists.remove(); } } //Initial check when the script loads handlePageChange(); //Use a MutationObserver to detect page changes in the SPA new MutationObserver(handlePageChange).observe(document.body, { childList: true, subtree: true }); })();