diff --git a/tdx-enhanced.js b/tdx-enhanced.js index 05d93f1..e92f590 100644 --- a/tdx-enhanced.js +++ b/tdx-enhanced.js @@ -1,7 +1,7 @@ // ==UserScript== // @name tdx-enhanced // @namespace ecn -// @version 2024-09-03-01 +// @version 2025-02-03-01 // @description enhanced tdx coloring & formatting. follows system color scheme. // @author Purdue STEM IT - it@purdue.edu // @match https://service.purdue.edu/TDNext/* @@ -67,6 +67,8 @@ 'zsite' : {'bg' : '#98A4AE', 'txt' : 'white'}, }; + var tdxtoolsUrl = "https://engineering.purdue.edu" + //regex for matching inline highlights var colorsByStatus = { '!!': {style: {background: 'var(--col-highlight-1)'}, type: 'highlight', re: new RegExp("\!! (.*) \!!","g")}, @@ -97,6 +99,25 @@ heading.style.color = q.txt parent.style.backgroundColor = q.bg } + handleHighlight("report",headingTxt,heading.parentElement) + + //try embedding + if (headingTxt.startsWith("{")) { + try { + let embedData = JSON.parse(headingTxt) + + let title = document.createElement("h4") + title.classList = heading.classList + title.innerText = embedData.name + let moduleBody = heading.parentNode.parentNode.querySelector(".ModuleContent") + let embed = document.createElement("iframe") + embed.classList = "customEmbed" + embed.src = embedData.url + heading.replaceWith(title) + moduleBody.replaceWith(embed) + } catch { + } + } } @@ -117,15 +138,17 @@ heading.appendChild(countSpan) } - var countTxt + var countTxt = null if (totalItems) { countTxt = `${numItems} of ${totalItems} ${totalItems == 1 ? 'item' : 'items'}` - } else { + } else if (numItems) { countTxt = `${numItems} ${numItems == 1 ? 'item' : 'items'}` } - countSpan.innerText = countTxt + if (countTxt) { + countSpan.innerText = countTxt + } } } @@ -143,24 +166,99 @@ let newFormat = "YYYY-MM-DDTHH:mm"; [...calendars].forEach(calendar=>{ let date = moment(calendar.value,originalFormat) - let iso = date.format(newFormat) let newCal = document.createElement("input") newCal.id = `${calendar.id}-new` newCal.classList = calendar.classList newCal.type = "datetime-local" - newCal.value = iso + + function updateDate() { + //update old tdx calendar + let parsedFormat = date.format(originalFormat) + calendar.value = parsedFormat + + //update new calendar + let iso = date.format(newFormat) + newCal.value = iso + calTxt.innerText = date.calendar() + + console.log("Cal update!",date) + } //convert to original format newCal.addEventListener("input",event=>{ let parsedValue = moment(event.target.value,newFormat) - let parsedFormat = parsedValue.format(originalFormat) - calendar.value = parsedFormat + date = parsedValue + updateDate() }) + //date modifier shortcuts + let calBox = document.createElement("div") + calBox.classList = ["calBox"] + let calTxt = document.createElement("span") + calTxt.innerText = date.format('dddd') + + //modify date + function btnModify(btn) { + console.log("Modify date:",btn) + if ('add' in btn) { + date.add(btn.add) + } else if ('set' in btn) { + date.set(btn.set) + } + + //check business days + let day = date.isoWeekday() + let hour = date.hour() + let min = date.minute() + let wkday = date.weekday() + + console.log("WkDay:",wkday,"Day:",day,"hour:",hour,"min:",min) + + //if Friday after 5pm + if (day>=5 && (hour>17 || (hour==17 && min>0))) { + date.set({ + h: 8, + d: 1+7, + m: 0 + }) + } else if (day>5) { + //if sat/sun + date.set({ + d: 1+7 + }) + } + + + updateDate() + } + + let buttons = [ + {name:"+1 day",add: {days:1}}, + {name:"+1 week",add: {weeks:1}}, + {name:"+1 month",add: {months:1}}, + {name:"12PM",set: {h:12,m:0}}, + {name:"5PM",set: {h:17,m:0}} + ] + + for (const btn of buttons) { + let button = document.createElement("button") + button.classList = "btn btn-calendar" + button.innerText = btn.name + button.addEventListener("click",(event)=>{ + event.preventDefault() + btnModify(btn) + }) + calBox.appendChild(button) + } + + updateDate() + //old input still needs to exist for proper format conversion calendar.style.display = "none" calendar.parentElement.append(newCal) + calendar.parentElement.append(calTxt) + calendar.parentElement.append(calBox) }); } @@ -271,6 +369,9 @@ let table = t.querySelector("table.report-viewer") let items = []; + var numItems = null + var totalItems = null + if (table) { let headers = []; //console.log("Table",table); @@ -309,8 +410,8 @@ }) //update panel heading above table - var numItems = items.length - var totalItems = null + numItems = items.length + //totalItems = null let pagination = t.querySelector(".pull-right .bootstrap-pagination-label") if (pagination) { @@ -319,10 +420,31 @@ totalItems = pTxt } - updateHeading(t.parentElement,numItems,totalItems) - console.log("Items:",items) + //console.log("Items:",items) } + + updateHeading(t.parentElement,numItems,totalItems) + } + + function createHighlightBubble(element,bgColor,txtColor) { + + //should the bubble carry links over? + //let copy = element.cloneNode(true) + + //create new element to highlight + let newSpan = document.createElement("span") + newSpan.innerText = element.innerText //item["2285"].txt + newSpan.style.backgroundColor = bgColor + newSpan.style.color = txtColor + newSpan.classList.add("qHighlight") + + //if we use the copy method + //newSpan.appendChild(copy) + + //replace cell with new span + element.replaceChildren(newSpan) + return newSpan } //modify/color the cells @@ -335,15 +457,7 @@ if (qTxt in colorsByQueue) { let q = colorsByQueue[qTxt] - //create new element to highlight - let newSpan = document.createElement("span") - newSpan.innerText = item["2285"].txt - newSpan.style.backgroundColor = q.bg - newSpan.style.color = q.txt - newSpan.classList.add("qHighlight") - - //replace cell with new span - qCell.replaceChildren(newSpan) + createHighlightBubble(qCell,q.bg,q.txt) } } @@ -394,9 +508,10 @@ let hours = duration.asHours() let alpha = hours / ageThreshold + alpha = alpha > 1 ? 1 : alpha let cell = modDate.cell - cell.style.background = `rgba(255,0,0,${alpha}` + handleHighlight("dateModified",alpha,cell) cell.classList.add(alpha > 0.5 ? "light" : "dark") } } @@ -409,34 +524,29 @@ //reply from user if (fromUser.txt == lastModified.txt && fromUser.txt != assignedTo.txt && assignedTo.txt != "Unassigned") { - item.row.style.backgroundColor = "var(--col-reply)"; + //item.row.style.backgroundColor = "var(--col-reply)"; + handleHighlight("reply",null,item.row) } //modified by internal if (lastModified.txt != fromUser.txt && lastModified.txt != assignedTo.txt) { let cell = item.LastModifiedByFullName.cell - cell.style.backgroundColor = "var(--col-modified)" + //cell.style.backgroundColor = "var(--col-modified)" + handleHighlight("userModified",null,cell) } } + //find internal users and highlight them + if ('ResponsibleFullName' in item) { + handleHighlight("person",item.ResponsibleFullName.txt,item.ResponsibleFullName.cell) + } else if ('Responsibility' in item) { + handleHighlight("person",item.Responsibility.txt,item.Responsibility.cell) + } + //find inline highlights for tasks if ('Title' in item) { let title = item.Title - for (const [key,color] of Object.entries(colorsByStatus)) { - let re = color.re.exec(title.txt) - if (re) { - let newTitle = re[1] - - let link = title.cell.querySelector("a") - if (link) { - title.cell.style.backgroundColor = color.style.background - link.innerText = newTitle - } - - //reset regex - color.re.lastIndex = 0 - } - } + handleHighlight("title",title.txt,title.cell) } //find links & open in new tab, if configured @@ -526,6 +636,92 @@ } + function handleHighlight(type, txt, element) { + + var re + var style = null + + for (const [key,color] of Object.entries(colorsByStatus)) { + re = color.re.exec(txt) + if (re) { + style = color.style + break + } + } + + const customHighlights = settings('get','customHighlights') || [] + for (const customHighlight of customHighlights) { + let customType = customHighlight.type + if (customType=="highlight") { + let char = customHighlight.value + let reg = new RegExp(`\\${char} (.*) \\${char}`,"g") + re = reg.exec(txt) + if (re) { + style = customHighlight.style + break + } + } + + if (type=="reply" && customType=="reply") { + style = customHighlight.style + } + + if (type=="dateModified" && customType=="dateModified") { + style = customHighlight.style + if (style.background) { + let a = Math.floor(txt * 255).toString(16); + style.background = style.background + a + } + } + + if (type=="userModified" && customType=="userModified") { + style = customHighlight.style + } + + if (type=="report" && customType=="report") { + if (customHighlight.value==txt) { + style = customHighlight.style + } + } + + if (type=="person" && customType=="person") { + if (customHighlight.value==txt) { + element = createHighlightBubble(element) + style = customHighlight.style + } + } + } + + if (style) { + //console.log("Apply custom highlight:",txt) + + let link = element.querySelector("a") + if (re && link) { + let newTitle = re[1] + link.innerText = newTitle + //reset regex + re.lastIndex = 0 + } + + for (const [attr,val] of Object.entries(style)) { + element.style[attr] = val + } + //element.style.backgroundColor = style.background + + } else { + //apply defaults + if (type=="reply") { + element.style.backgroundColor = "var(--col-reply)"; + } + if (type=="userModified") { + element.style.backgroundColor = "var(--col-modified)"; + } + if (type=="dateModified") { + element.style.backgroundColor = `rgba(255,0,0,${txt}`; + } + } + } + function generatePopup(href,w,h,l,t,source) { } @@ -789,6 +985,13 @@ +