// ==UserScript==
// @name Job Search Highlighting
// @namespace https://github.com/ChrisMBarr/UserScripts
// @version 0.97
// @description Highlights key words and locations on many popular job sites
// @author Chris Barr
// @homepageURL https://github.com/ChrisMBarr/UserScripts
// @updateURL https://github.com/ChrisMBarr/UserScripts/raw/main/src/job-search-highlighting.user.js
// @match *://*.applytojob.com/*
// @match *://*.avature.net/*/careers/JobDetail/*
// @match *://*.dejobs.org/*
// @match *://*.dice.com/job-detail/*
// @match *://*.dice.com/jobs*
// @match *://*.dice.com/dashboard/intellisearch-jobs/*
// @match *://*.glassdoor.com/Job*
// @match *://*.glassdoor.com/job-listing/*
// @match *://boards.greenhouse.io/*/jobs/*
// @match *://app.honestjobs.com/job-seeker/dashboard/job-search
// @match *://*.icims.com/jobs/*
// @match *://*.indeed.com/*
// @match *://*.apply.indeed.com/*
// @match *://*.jobot.com/*
// @match *://*.jobsfordevelopers.com/jobs/*
// @match *://*.jobs.lever.co/*
// @match *://*.linkedin.com/jobs/*
// @match *://*.myworkdayjobs.com/*/job/*
// @match *://*.nowhiteboard.org/jobs/*
// @match *://*.remote.co/job/*
// @match *://*.remotejobs.com/*
// @match *://*.remoteok.com/remote-jobs/*
// @match *://*.roberthalf.com/*/*/job*
// @match *://app.smartmatchjobs.com/smart_job_searches/job_vacancy_detail*
// @match *://jobs.smartrecruiters.com/*/*
// @match *://*.startup.jobs/*
// @match *://app.testedrecruits.com/posting/*
// @match *://*.themuse.com/jobs/*
// @match *://*.recruiting.ultipro.com/*/JobBoard/*
// @match *://*.wellfound.com/*
// @match *://*.workatastartup.com/jobs/*
// @match *://*.workingnomads.com/*
// @match *://*.ziprecruiter.com/jobs/*
// @match *://*.ziprecruiter.com/ojob/*
// @icon https://www.indeed.com/images/favicon.ico
// @grant GM_addStyle
// @noframes
// @require http://code.jquery.com/jquery-3.4.1.min.js
// @require http://bartaz.github.io/sandbox.js/jquery.highlight.js
// @require https://gist.github.com/raw/2625891/waitForKeyElements.js
// ==/UserScript==
(function () {
"use strict";
var $ = window.jQuery;
//Options for additional things to flag in the words list
const flagSecurityClearances = true;
const flagCriminalRecord = false;
//A list of terms to always highlight
const descriptionAlwaysHighlight = ["angular", "typescript", "type script", "javascript", "java script", "css", "scss", "html"];
//a list of terms to always highlight, but with a red/flagged color. These are things to be alerted about
const descriptionAlwaysFlag = [
"initially remote",
"not available to",
"employment is contingent upon",
"will not be considered",
"may be required",
"should be able to",
"must be able to",
"should be comfortable",
"must be comfortable",
"is a must",
"must have",
"must be",
"Must possess",
"required",
"able to use",
"is a requirement",
"Experience with",
"Experience in ", //intentional space here to avoid flagging part of "experience including" (for example)
"Experienced with",
"Experienced in ", //intentional space here to avoid flagging part of "experience including" (for example)
"deep understanding of",
"deep knowledge of",
"mastery of",
"do not apply if",
"encouraged to apply",
"are encouraged to",
"encourage you to",
"must be located in",
"must reside in",
"must live in",
];
if (flagSecurityClearances) {
descriptionAlwaysFlag.push(
...[
"ability to obtain",
"able to obtain",
"TS/SCI",
"DoD Secret",
"DoE Secret",
"Top Secret/Sensitive Compartmented Information",
"top secret clearance",
"top secret level clearance",
"top secret level security clearance",
"secret clearance",
"secret level clearance",
"secret level security clearance",
"public trust clearance",
"public trust",
"security clearance",
"Q clearance",
"L clearance",
"government background investigation",
]
);
}
if (flagCriminalRecord) {
descriptionAlwaysFlag.push(
...[
"background investigation",
"background check",
"fair chance",
"conviction record",
"arrest record",
"criminal history",
"criminal histories",
"criminal record",
"criminal",
"felony",
"felonies",
]
);
}
//Work types that are highlighted in a different color
const workTypesAlwaysHighlight = [
"not c2c",
"no c2c",
"not a C2C",
"No third-party/C2C",
"c2c",
"ctc",
"corp-to-corp",
"corp to corp",
"freelance",
"fulltime",
"full time",
"full-time",
"parttime",
"part time",
"part-time",
"contract to hire",
"contract-to-hire",
"c2h",
"contract",
"w2",
"1099",
"100% remote",
"completely remote",
"entirely remote",
"totally remote",
"fully remote",
"remote position",
];
//Just "remote" or any location that includes specific words like "remote in Charlotte, NC"
//This way we don't highlight results like "Remote from Las Vegas, NM" - although it is remote, you don't live there
const locationHighlightPattern =
/(^remote(,? \(?US.?\)?)?$)|(^U.?S.?\s|-remote$)|(^remote[;–\- ]*united states$)|(^remote or.+)|United States;? \(?Remote\)?|(^hybrid remote$)|charlotte|, nc|north carolina/i;
//Matches mentions of currency or currency ranges
//Ex: "$65" "$65.00" "$65K" "$65,000" "$1B" "$50/hr" "$50 per hour" "$40 - 50 per hour" "$75K per year"
const currencyHighlightPattern =
/([$£€][\d,.]+\s*((hundred|thousand|million|billion|trillion)|[KMB])?\+?((\s*(to|-|–)\s*)?[$£€]?[\d,.]+[KMB]?)?)(\s*\/?(|pe?r)\s*(hr|hour|month|week|yr|year|annually|annual|annum))?/gi;
//------------------------------------------------------------------------------------------------------------
// HIGHLIGHTING STYLES
//------------------------------------------------------------------------------------------------------------
//.jsh-mark is added to all highlight types
const highlightStyles = `
.jsh-mark {
position: relative !important;
outline-width: 1px;
outline-style: solid;
border-radius: 0.25rem;
cursor: help;
top: 0 !important;
right: 0 !important;
bottom: 0 !important;
left: 0 !important;
}
.jsh-mark::before {
display:none;
position: absolute;
bottom: 1.25rem;
left: 0;
width: 150px;
padding: 0.25rem;
font-size: 12px;
font-weight: normal;
line-height: 1.1;
color: hsl(50, 60%, 40%);
background-color: hsl(50, 95%, 90%);
border: 1px solid hsl(50, 60%, 70%);
border-radius: 0.5rem;
box-shadow: 0 0.15rem 0.5rem rgba(45,45,45,0.15);
}
.jsh-mark:hover::before {
display: block;
}
.jsh-always-highlight {background-color:hsla(46,100%,70%,0.5); outline-color:hsla(46,100%,50%,0.5);}
.jsh-always-highlight:hover {outline-color:hsla(46,100%,50%,1);}
.jsh-always-highlight::before {content:'Job Search Highlighter: You specified this word or phrase to always be highlighted';}
.jsh-location {background-color:hsla(28,100%,80%,0.75); outline-color:hsla(28,90%,60%,0.75);}
.jsh-location:hover {outline-color:hsla(28,90%,60%,1);}
.jsh-location::before {content:'Job Search Highlighter: This location matches the pattern you specified';}
.jsh-search-term {background-color:hsla(203,100%,90%,0.75); outline-color:hsla(203,90%,75%,0.75);}
.jsh-search-term:hover {outline-color:hsla(203,90%,75%,1);}
.jsh-search-term::before {content:'Job Search Highlighter: You searched for this word or phrase on this website';}
.jsh-flagged {background-color:hsla(0,80%,80%,0.75); outline-color:hsla(0,70%,70%,0.75);}
.jsh-flagged:hover {outline-color:hsla(0,70%,70%,1);}
.jsh-flagged::before {content:'Job Search Highlighter: You specified this as a flagged term that you should be made aware of';}
.jsh-work-type {background-color:hsla(268,100%,90%,0.75); outline-color:hsla(268,85%,85%,0.75);}
.jsh-work-type:hover {outline-color:hsla(268,85%,85%,1);}
.jsh-work-type::before {content:'Job Search Highlighter: You marked this as a type of work';}
.jsh-currency {background-color:hsla(126,70%,80%,0.75); outline-color:hsla(126,70%,70%,0.75);}
.jsh-currency:hover {outline-color:hsla(126,70%,70%,1);}
.jsh-currency::before {content:'Job Search Highlighter: This matches a pattern that looks like it might mention a compensation amount';}
`;
let highlightStylesEl = GM_addStyle(highlightStyles);
//------------------------------------------------------------------------------------------------------------
// Highlighting logic
//------------------------------------------------------------------------------------------------------------
let searchParam = "";
let paramsToSearch = location.search; //default
function highlightSearchParam($node) {
if (searchParam.length > 0) {
const params = new URLSearchParams(paramsToSearch);
const searchQuery = params.get(searchParam);
if (searchQuery) {
[...searchQuery.matchAll(/"(.+?)"|[\w-]+/g)].forEach((q) => {
//prefer match 1 first with the quoted string, then look for the other one
if (q[1]) {
$node.highlight(q[1].replace(/"/g, ""), {
className: "jsh-mark jsh-search-term",
});
} else if (q[0]) {
//no quoted string found, so just search for whatever else was matched
$node.highlight(q[0], { className: "jsh-mark jsh-search-term" });
}
});
}
}
}
function highlightJobDesc(jNode) {
const $node = $(jNode);
//Find words to highlight from the search parameters
highlightSearchParam($node);
//Highlight mentions of currency
$node.each((_i, n) => {
[...n.innerHTML.matchAll(currencyHighlightPattern)].forEach((m) => {
$(n).highlight(m[0], { className: "jsh-mark jsh-currency" });
});
});
//always highlight these words
$node.highlight(descriptionAlwaysHighlight, {
className: "jsh-mark jsh-always-highlight",
});
$node.highlight(descriptionAlwaysFlag, {
className: "jsh-mark jsh-flagged",
});
$node.highlight(workTypesAlwaysHighlight, {
className: "jsh-mark jsh-work-type",
});
}
function highlightLocation(jNode, textNodesOnly) {
$(jNode).each((_i, n) => {
let txt = n.innerText;
if (textNodesOnly) {
//This will ignore text from any child nodes
txt = [...n.childNodes]
.filter((c) => c.nodeType === 3)
.map((c) => c.nodeValue)
.join("");
}
txt = txt
.replace(/^location:/i, "")
.replace(/[\n\r]+/gi, " ")
.trim();
if (locationHighlightPattern.test(txt)) {
$(n).highlight(txt, { className: "jsh-mark jsh-location" });
}
});
}
//------------------------------------------------------------------------------------------------------------
// Helper Functions
//------------------------------------------------------------------------------------------------------------
function runForHostname(partialUrl, fn) {
if (location.hostname.toLowerCase().includes(partialUrl.toLowerCase())) fn(location.pathname.toLowerCase());
}
function selectSingleNode(selector) {
return document.querySelector(selector);
}
function selectNodes(selector) {
return document.querySelectorAll(selector);
}
const defaultDelayTime = 1000; //1 second
function runAfterDelay(fn, time) {
if (!time) time = defaultDelayTime;
setTimeout(fn, time);
}
function runOnInterval(fn) {
setInterval(fn, defaultDelayTime);
}
function reApplyStyles() {
const id = highlightStylesEl.id;
//these generated IDs contain a dot which is technically invalid and that breaks jQuery and querySelector, but not getElementById
const styleNode = document.getElementById(id);
if (styleNode == null) {
highlightStylesEl = GM_addStyle(highlightStyles);
}
}
//------------------------------------------------------------------------------------------------------------
// Website-specific elements
//------------------------------------------------------------------------------------------------------------
//===========
//APPLY TO JOB (recruitment/application site some companies use, no job searching)
runForHostname("applytojob.com", (path) => {
waitForKeyElements("#job-description", highlightJobDesc);
waitForKeyElements('.job-attributes-container [title="Location"]', highlightLocation);
});
//AVATURE (recruitment/application site some companies use, no job searching)
runForHostname("avature.net", (path) => {
waitForKeyElements(".article--details .article__content", highlightJobDesc);
});
//===========
//DEJOBS (recruitment/application site some companies, no job searching)
runForHostname("dejobs.org", (path) => {
waitForKeyElements("#direct_jobDescriptionText", highlightJobDesc);
waitForKeyElements('#direct_jobListingTitle [itemprop="jobLocation"]', highlightLocation);
});
//===========
//DICE
runForHostname("dice.com", (path) => {
searchParam = "q";
//Show full descriptions on the search results page. This also prevents the tooltips from being cut off
GM_addStyle(
`.search-card .card-description{overflow:visible !important; max-height:none !important; -webkit-line-clamp:none !important;}`
);
if (path.startsWith("/job-detail/")) {
//individual job detail page
//On this page the return search QS is stored as a param itself which we can parse
const encodedSearchParams = new URLSearchParams(location.search).get("searchlink");
if (encodedSearchParams) {
paramsToSearch = encodedSearchParams.replace("search/?", "");
}
runAfterDelay(() => {
//auto-expand the job description
$("#descriptionToggle").click();
waitForKeyElements("#jobDescription", highlightJobDesc);
waitForKeyElements('.companyInfo li[data-cy="companyLocation"]', highlightLocation);
});
} else {
//ajax job search page or intellisearch jobs page
waitForKeyElements(".search-result-location", highlightLocation, false);
waitForKeyElements(".card-description", highlightJobDesc, false);
}
});
//===========
//GLASS DOOR
runForHostname("glassdoor.com", (path) => {
if (path.startsWith("/job")) {
//job search page
searchParam = "sc.occupationParam";
//Force the job details to appear expanded, clicking the button doesn't seem to work
GM_addStyle(
`[class^='JobDetails_jobDescription']{max-height:none; mask-image:none; -webkit-mask-image:none;}
#JobDescriptionContainer > [id^='JobDesc']{max-height:none; overflow:visible;}
.jobDescriptionContent{overflow:visible;}`
);
waitForKeyElements("[data-test='location'], [data-test='emp-location']", highlightLocation, false);
waitForKeyElements(
"[class^='JobDetails_jobDescription'], #JobDescriptionContainer [id^='JobDesc']",
highlightJobDesc,
false
);
} else if (path.startsWith("/job-listing/")) {
//job details page
waitForKeyElements("[data-test='location']", highlightLocation);
waitForKeyElements("#JobDescriptionContainer", highlightJobDesc);
}
});
//===========
//GREENHOUSE
runForHostname("greenhouse.io", (path) => {
waitForKeyElements("#header .location", highlightLocation);
waitForKeyElements("#content", highlightJobDesc);
});
//===========
//ICIMS (recruitment/application site some companies, no job searching)
runForHostname("icims.com", (path) => {
runAfterDelay(() => {
//Insert styles and highlight within the iframe
const iframeDoc = document.querySelector("#icims_content_iframe").contentWindow.document;
const iframeStyles = iframeDoc.createElement("style");
iframeStyles.innerText = highlightStyles;
iframeDoc.body.appendChild(iframeStyles);
highlightLocation(iframeDoc.querySelectorAll(".iCIMS_JobsTable .header.left span:nth-child(2)"));
highlightJobDesc(iframeDoc.querySelectorAll(".iCIMS_InfoMsg_Job"));
});
});
//===========
//INDEED
runForHostname("indeed.com", (path) => {
searchParam = "q";
//Improve the look of the currently selected job - a more visible shadow/glow
GM_addStyle(`.mosaic-provider-jobcards .desktop.vjs-highlight .slider_container{
box-shadow: 0 0.125rem 0.25rem rgba(0,0,0,.5), 0 0 0.8rem rgba(37, 87, 167,.5);
}`);
if (path.startsWith("/job/") || path.startsWith("/viewjob")) {
//static individual job details page
waitForKeyElements("#jobDescriptionText", highlightJobDesc);
waitForKeyElements(".jobsearch-CompanyInfoWithReview > div > div > div:nth-child(2)", highlightLocation);
} else if (path.includes("/indeedapply/")) {
//The final submit/confirm page - auto scroll to the button
//NOTE: Both INDEED and GLASSDOOR will use this page!
waitForKeyElements(".ia-continueButton", (node) => {
if ($(node).is('button:contains("Submit your application")')) {
setTimeout(() => {
node[0].scrollIntoView({ behavior: "smooth" });
}, 500);
}
});
} else {
//ajax job search page
runOnInterval(() => {
highlightJobDesc($("#jobDescriptionText"));
highlightLocation(
$(
"#mosaic-provider-jobcards .company_location [data-testid='text-location'], #mosaic-provider-jobcards .company_location [data-testid='text-location'] span"
),
true
);
highlightLocation(
$(
'.jobsearch-CompanyInfoWithReview [data-testid="inlineHeader-companyLocation"], .jobsearch-CompanyInfoWithoutHeaderImage [data-testid="inlineHeader-companyLocation"]'
)
);
});
}
});
//===========
//HONEST JOBS
runForHostname("honestjobs.com", (path) => {
//Fix the border width not to jump when hovered over
GM_addStyle(`.job-search-result-item{border-width:2px !important;}`);
waitForKeyElements(".mat-dialog-content .job-desc", highlightJobDesc, false);
});
//===========
//JOBOT
runForHostname("jobot.com", (path) => {
searchParam = "q";
//More clear highlighting of the current job
GM_addStyle(`.search-result .job.selected{box-shadow: 0 0 0.8rem #23b3e7;border-radius:10px 0 0 10px;}`);
//This is a single-page app so we cannot check for URLs since the page never reloads
//We need to wait a bit for the app to initialize and then it's good to go
runAfterDelay(() => {
waitForKeyElements(".JobDescription", highlightJobDesc, false);
waitForKeyElements(
".header-details li, .JobInfoCard .q-item__section--main, .JobInfoCard .q-item__section--main .content div",
highlightLocation,
false
);
});
});
//===========
//JOBS FOR DEVELOPERS
runForHostname("jobsfordevelopers.com", (path) => {
//Locations are easy to see on this site, and the format they use is different from other sites. Not worth highlighting locations for this site
waitForKeyElements(".container .prose", highlightJobDesc, false);
runOnInterval(reApplyStyles);
});
//===========
//LEVER (recruitment/application site some companies use, no job searching)
runForHostname("lever.co", (path) => {
waitForKeyElements(".posting-categories .location, .posting-categories .workplaceTypes", highlightLocation);
waitForKeyElements(".section-wrapper.page-full-width .section", highlightJobDesc);
});
//===========
//LINKEDIN
runForHostname("linkedin.com", (path) => {
searchParam = "keywords";
//auto-expand the description
waitForKeyElements(".jobs-description footer button", (n) => {
runAfterDelay(() => {
$(n).click();
});
});
runOnInterval(() => {
highlightJobDesc(selectNodes("#job-details"));
const locationEl = selectSingleNode(".jobs-unified-top-card__primary-description > div");
if (locationEl) {
const locationTextNode = Array.from(locationEl.childNodes).filter((n) => n.nodeType === 3 && n.data.trim() !== "")[0];
if (locationTextNode) {
locationTextNode.data = locationTextNode.data.replace("· ", "");
$(locationTextNode).wrap('');
const wrappedLocation = $("#LOCATION_FOR_HIGHLIGHT");
$("· ").insertBefore(wrappedLocation);
highlightLocation(wrappedLocation);
}
}
if (path.startsWith("/jobs/collections/") || path.startsWith("/jobs/search/")) {
//select additional items for the AJAX search
highlightLocation(selectNodes(".job-card-container__metadata-wrapper .job-card-container__metadata-item"));
}
});
});
//===========
//MY WORKDAY JOBS (recruitment/application site some companies use, no job searching)
runForHostname("myworkdayjobs.com", (path) => {
waitForKeyElements("#mainContent [data-automation-id='locations'] dd", highlightLocation);
waitForKeyElements("#mainContent [data-automation-id='jobPostingDescription']", highlightJobDesc);
});
//===========
//NO WHITEBOARD
runForHostname("nowhiteboard.org", (path) => {
waitForKeyElements(".job-header-info h3:nth-child(2)", highlightLocation);
waitForKeyElements(".job-important-info, .job-description", highlightJobDesc);
});
//===========
//REMOTE.CO
runForHostname("remote.co", (path) => {
waitForKeyElements(".location_sm", highlightLocation);
waitForKeyElements(".job_description", highlightJobDesc);
});
//===========
//REMOTE JOBS
runForHostname("remotejobs.com", (path) => {
GM_addStyle(`.dark .jsh-mark{color:#000;}`); //dark site BG has white text normally, this makes the highlighting readable
waitForKeyElements("main.notion-page", highlightJobDesc);
});
//===========
//REMOTE OK
runForHostname("remoteok.com", (path) => {
GM_addStyle(`.jsh-mark{color:#000;}`); //dark site BG has white text normally, this makes the highlighting readable
waitForKeyElements("#jobsboard .active .description", highlightJobDesc);
});
//===========
//ROBERT HALF
runForHostname("roberthalf.com", (path) => {
waitForKeyElements(
"rhcl-job-card [data-testid='job-details-description'], rhcl-job-card [data-testid='job-details-requirements']",
highlightJobDesc
);
//Add a link to each card to add a link to open the job application in a new window - their current site is awful for applying to multiple jobs!
waitForKeyElements("rhcl-job-card", (node) => {
const jobId = node[0].attributes["job-id"].value;
const applyUrl = `https://www.roberthalf.com/us/en/apply/app?jobId=${jobId}`;
let applyLink = node[0].parentElement.querySelector(".helper-apply-link");
if (applyLink) {
applyLink.setAttribute("href", applyUrl);
} else {
applyLink = document.createElement("a");
applyLink.setAttribute("class", "helper-apply-link");
applyLink.setAttribute("href", applyUrl);
applyLink.setAttribute("target", "_blank");
applyLink.setAttribute("style", "display: inline-block;padding: .5rem 0;");
applyLink.innerText = "Apply on new page";
node[0].parentElement.prepend(applyLink);
}
});
});
//===========
//TESTED RECRUITS (recruitment/application site some companies use, no job searching)
runForHostname("testedrecruits.com", (path) => {
waitForKeyElements(".description", highlightJobDesc);
});
//===========
//THE MUSE
runForHostname("themuse.com", (path) => {
waitForKeyElements("[class^=JobIndividualHeader_jobHeaderLocation__]", highlightLocation);
waitForKeyElements("[class^=JobIndividualBody_jobBodyDescription__] > *:not([class^=JobAlert])", highlightJobDesc);
});
//===========
//ULTIPRO (recruitment/application site some companies use)
runForHostname("ultipro.com", (path) => {
runAfterDelay(() => {
//Expand all job locations
$('[data-automation="job-location-more"]').each((i, x) => x.click());
if (path.includes("/opportunitydetail")) {
//specific job posting
waitForKeyElements(".opportunity-sidebar [data-automation='physical-location'] > *", highlightLocation, false);
waitForKeyElements(".opportunity-description", highlightJobDesc, false);
} else {
//listing/search page
searchParam = "q";
waitForKeyElements(".opportunity .location-bottom", highlightLocation, false);
waitForKeyElements(".opportunity > [data-automation='job-brief-description']", highlightJobDesc, false);
}
});
});
//===========
//SMART MATCH JOBS (recruitment/application site some companies use)
runForHostname("smartmatchjobs.com", (path) => {
waitForKeyElements(".main-content-box", highlightJobDesc);
});
//===========
//SMART RECRUITERS (recruitment/application site some companies use)
runForHostname("smartrecruiters.com", (path) => {
waitForKeyElements(".c-spl-job-location__place", highlightLocation);
waitForKeyElements(".job-sections", highlightJobDesc);
});
//===========
//STARTUP.JOBS
runForHostname("startup.jobs", (path) => {
waitForKeyElements(".jobListing__main__text", highlightJobDesc);
waitForKeyElements(".jobListing__main__meta__remote", highlightLocation);
//Location highlighting for the ajax search
waitForKeyElements(".content-wrapper [data-post-template-target='location']", highlightLocation, false);
});
//===========
//WELL FOUND
runForHostname("wellfound.com", (path) => {
waitForKeyElements("[class^='styles_description__']", highlightJobDesc);
});
//===========
//WORK AT A STARTUP (Y COMBINATOR)
runForHostname("workatastartup.com", (path) => {
waitForKeyElements(".company-details > div:first-child > div", highlightLocation);
waitForKeyElements(".company-details .prose", highlightJobDesc);
});
//===========
//WORKING NOMADS
runForHostname("workingnomads.com", (path) => {
waitForKeyElements(
"#mobile-job-detail .detailRows .detailRow:nth-child(2) span, #div-item-data .about-job-lines .about-job-line:nth-child(2) .about-job-line-text",
highlightLocation
);
waitForKeyElements("#mobile-job-detail .jobDescription ~ *, #div-item-data .job-desktop-description ~ *", highlightJobDesc);
});
//===========
//ZIP RECRUITER
runForHostname("ziprecruiter.com", (path) => {
waitForKeyElements(".job_description", highlightJobDesc);
waitForKeyElements(".job_header .hiring_location", highlightLocation);
//auto-expand the description
$(".job_details_tile").addClass("clicked");
});
})();