Skip to content

Instantly share code, notes, and snippets.

@zhouqt
Forked from roylez/SFreadability.user.js
Last active January 13, 2021 08:31
Show Gist options
  • Save zhouqt/a1ec7eb01e9b5814f121a27dd5f812e2 to your computer and use it in GitHub Desktop.
Save zhouqt/a1ec7eb01e9b5814f121a27dd5f812e2 to your computer and use it in GitHub Desktop.
// ==UserScript==
// @name SFreadability-modified
// @namespace http://tampermonkey.net/
// @version 0.751
// @history 0.751 Merge from roylez's version
// @history 0.75 adjust comments section max-width
// @history 0.74 Hightlight last update date fields in case listings
// @history 0.73 Color code last updated time in case listing
// @history 0.721 Add functions to handle console page
// @history 0.72 Add call history tab 2020-03-06 (zhouqt)
// @history 0.71 Handle files without extensions 2020-03-03
// @history 0.7 Handle attachments with same names 2020-02-14 (zhouqt)
// @history 0.6 Adapt to changes in SF UI change in 2020-02
// @description SalesForce readability
// @author roylez
// @include https://*.my.salesforce.com/500*
// @license MIT
// @grant GM_addStyle
// @require https://code.jquery.com/jquery-2.2.4.min.js
// @require https://code.jquery.com/ui/1.12.1/jquery-ui.min.js
// @require https://unpkg.zhimg.com/dayjs
// @updateURL https://gist.github.com/zhouqt/a1ec7eb01e9b5814f121a27dd5f812e2/raw/SFreadability-modified.user.js
// @downloadURL https://gist.github.com/zhouqt/a1ec7eb01e9b5814f121a27dd5f812e2/raw/SFreadability-modified.user.js
// @run-at document-idle
// ==/UserScript==
GM_addStyle ( `
.salesforce_comment.public {
border-left: 3px solid #82b74b !important
}
.entityFeedLayout .mainSection {
padding-left: 0;
background: initial;
}
.entityFeedLayout .leftContent {
display: none;
}
.efpPanelSelect.efpsTopTabs.efpViewSelect { display: none; }
.pbBottomButtons { display: none; }
.comments { max-width: 90vw; }
` );
this.$ = this.jQuery = jQuery.noConflict(true)
$.fn.renameTag = function(replaceWithTag){
this.each(function(){
var outerHtml = this.outerHTML;
var tagName = $(this).prop("tagName");
var regexStart = new RegExp("^<"+tagName,"i");
var regexEnd = new RegExp("</"+tagName+">$","i")
outerHtml = outerHtml.replace(regexStart,"<"+replaceWithTag)
outerHtml = outerHtml.replace(regexEnd,"</"+replaceWithTag+">");
$(this).replaceWith(outerHtml);
});
return this;
}
// https://gist.github.com/BrockA/2625891
function waitForKeyElements (
selectorTxt, /* Required: The jQuery selector string that
specifies the desired element(s).
*/
actionFunction, /* Required: The code to run when elements are
found. It is passed a jNode to the matched
element.
*/
bWaitOnce, /* Optional: If false, will continue to scan for
new elements even after the first match is
found.
*/
iframeSelector /* Optional: If set, identifies the iframe to
search.
*/
) {
var targetNodes, btargetsFound;
if (typeof iframeSelector == "undefined")
targetNodes = $(selectorTxt);
else
targetNodes = $(iframeSelector).contents ()
.find (selectorTxt);
if (targetNodes && targetNodes.length > 0) {
btargetsFound = true;
/*--- Found target node(s). Go through each and act if they
are new.
*/
targetNodes.each ( function () {
var jThis = $(this);
var alreadyFound = jThis.data ('alreadyFound') || false;
if (!alreadyFound) {
//--- Call the payload function.
var cancelFound = actionFunction (jThis);
if (cancelFound)
btargetsFound = false;
else
jThis.data ('alreadyFound', true);
}
} );
}
else {
btargetsFound = false;
}
//--- Get the timer-control variable for this selector.
var controlObj = waitForKeyElements.controlObj || {};
var controlKey = selectorTxt.replace (/[^\w]/g, "_");
var timeControl = controlObj [controlKey];
//--- Now set or clear the timer as appropriate.
if (btargetsFound && bWaitOnce && timeControl) {
//--- The only condition where we need to clear the timer.
clearInterval (timeControl);
delete controlObj [controlKey]
}
else {
//--- Set a timer, if needed.
if ( ! timeControl) {
timeControl = setInterval ( function () {
waitForKeyElements ( selectorTxt,
actionFunction,
bWaitOnce,
iframeSelector
);
},
300
);
controlObj [controlKey] = timeControl;
}
}
waitForKeyElements.controlObj = controlObj;
}
function always_show_details() {
$(".lowerMainSection").remove()
$(".eflDetails").attr("style", "")
}
function remake_header() {
let header = $(".headerContent")
let title = header.find(".efhpTitle").first().text()
let customer = header.find(".efhpContainer > table > tbody > tr > td.efhpLeftContent > div:nth-child(2) > span > div a")
let number = header.find(".efhpContainer > table > tbody > tr > td.efhpCenterContent > div > div.efhpCenterTopRow > span:nth-child(3) > span")
let created = header.find(".efhpContainer > table > tbody > tr > td.efhpCenterContent > div > div.efhpCenterTopRow > span:nth-child(6)")
let status = header.find(".efhpContainer > table > tbody > tr > td.efhpRightContent > table > tbody > tr:nth-child(1) > td.efhpValue.efhpLargeRow > div > span")
let severity = header.find(".efhpContainer > table > tbody > tr > td.efhpRightContent > table > tbody > tr:nth-child(2) > td.efhpValue.efhpLargeRow > div > span")
let owner = header.find(".efhpContainer > table > tbody > tr > td.efhpRightContent > table > tbody > tr:nth-child(3) > td.efhpValue.efhpLargeRow > div > a")
header.children().remove()
header.append($(`<h1 class="f1 fw2 black-90 mv2">${title}</h1>`))
}
function inject_css() {
$("head").append('<meta name="viewport" content="width=device-width, initial-scale=1">')
$("head").append('<link ' + 'href="//code.jquery.com/ui/1.12.1/themes/smoothness/jquery-ui.css" ' + 'rel="stylesheet" type="text/css">')
$("head").append('<link ' + 'href="//unpkg.zhimg.com/tachyons@4/css/tachyons.min.css" ' + 'rel="stylesheet" type="text/css">')
}
function do_move_sections(list, tab) {
list.children(".bRelatedList").each(function() {
var t = $(this).find(".pbTitle h3").text()
var id = $(this).attr('id')
if ( t = t.match(/(Emails|Time Cards|Team|Comments|Files|Case History|Activity History)/) ) {
t = t[0]
if ( t == "Emails" ) { t = "📧" + t }
else if ( t == "Time Cards" ) { t = "🕔" + t }
else if ( t == "Team" ) { t = "🙉" + t }
else if ( t == "Comments") { t = "✍️" + t }
else if ( t == "Files" ) { t = "📁" + t }
else if ( t == "Case History" ) { t = "🍉History" }
else if ( t == "Activity History" ) { t = "📞Activity" }
tab.append($("<li class='f6'><a href='#" + id + "'>" + t + "</a></li>"))
} else {
$(this).remove()
}
})
}
function move_sections() {
// move related lists to tabs
var list = $(".efdRelatedLists")
if ( list.children(".bRelatedList").size() == 0 ) {
return 0
}
list.children(".fewerMore").remove()
let comments = list.children(".bRelatedList:has(#comments)")
list.prepend(comments)
list.prepend($("<ul/>"))
var tab = list.children("ul")
do_move_sections(list, tab)
list.tabs({ active: 0 })
}
function move_sections_console() {
// Aviod breaking normal case list pages.
if ( window.self == window.top) {
return 0
}
var list = $(".oRight")
if (list.children(".bRelatedList").size()== 0 ) {
return 0
}
list.children(".fewerMore").remove()
var div = $("<div class='ui-tabs-panel ui-corner-bottom ui-widget-content' />")
div.insertBefore(list.find(".bRelatedList").first())
var tab = $("<ul />")
div.prepend(tab)
do_move_sections(list, tab)
list.tabs({ active: 1 })
}
function clear_comments() {
var attachments = $(".pbBody[id$=RelatedFileList_body]").first()
// replace table with div
var table = $(".pbBody[id*='CommentsList'] > table")
table.parent().prepend("<div id='comments' class='db mw9 center sans-serif f5'/>")
var div=table.parent().children().first()
table.find("tr.dataRow").each(function() {
div.append("<div class='comment_row flex items-center bb bw1 b--light-blue dark-gray'/>")
var row = div.children().last()
var title = $(this).find(".dataCell b").first()
var author = $(this).find(".dataCell b a").first()
var time = title.text().match(/\((\d+\/\d+\/\d{4}, \d+:\d+.*?)\)/)
time = time[1]
var content = $(this).children().last()
title.remove()
content.find("br").first().remove()
row.append("<div class='w-20-ns tc pa3'>" + $(this).children(".actionColumn").html() + "</div>")
var has_attachment=content.text().match(/New File added: (.*?) \[/)
// comment says there is an attachment
if ( has_attachment ) {
var attachment_name=has_attachment[1].replace(/\.[^.]+$/, '')
var candidates = attachments.find( `tr:contains('${attachment_name}')` )
// attachment actually found in the list without going to next page
if ( candidates.length == 1 ) {
content = mark_attachment(has_attachment[1], time, candidates.first())
} else if (candidates.length > 1) {
candidates.each(function() {
var match = $(this).text().match(time)
if ( match && match.length == 1) {
content = mark_attachment(has_attachment[1], time, $(this).first())
}
})
}
}
row.append("<div class='w-80-ns pa3 courier f5'>" + content.prop('outerHTML') + "</div>")
var action_column = row.children().first()
var action_button = action_column.text()
var author_text = author.text()
// highlight public comments and comments from customers
if ( /(portal|NTT)/.test(author_text) ) {
row.addClass("bg-light-yellow")
} else if ( /Private/.test(action_button) ) {
row.addClass("bg-lightest-blue")
}
action_column.prepend("<p class='comment_time'><b>" + time + "</b></p>")
action_column.prepend("<p><b>" + author.get(0).outerHTML + "</b></p>")
})
table.remove()
}
function mark_attachment(file, time, attachment_row) {
var link = attachment_row.find("td a.actionLink:contains('Download')").attr('href')
var button = $(`<a class="f7 no-underline link dim br2 ba bw1 ph3 pv2 mb2 dib mid-gray b--blue" target="_blank" href="${link}">${file}</a>`)
return button
}
function move_comment_form() {
let iframe = $( ".efdFields " ).children(":has(iframe)")
iframe.nextAll().before(iframe)
}
// must place this before moving comment form
function set_comment_defaults() {
var iframe = $( "iframe[title=NewCaseComment]" )[0]
function time_delta(time) { return dayjs().diff(time, "minute") }
var frame_win = iframe.contentWindow ? iframe.contentWindow : iframe.contentDocument.defaultView
var last_comment_time = dayjs($(".comment_row:first-child .comment_time ").text())
function listener(event){
if ( event.data == "getTime" ) {
let diff = 5
if ( last_comment_time ) {
let delta = time_delta(last_comment_time)
diff = delta > 720 ? diff : delta
}
frame_win.postMessage({ timecard: diff }, "*")
}
}
var w;
if (typeof unsafeWindow != undefined) {
w = unsafeWindow
} else {
w = window;
}
w.addEventListener("message",listener,false)
}
function style_description() {
let des = $("#cas15_ileinner")
des.addClass("f6 bg-light-yellow code pv2")
}
// class="x-grid3-col-CASES_LAST_UPDATE"
function colorize_cases_last_update() {
let now = dayjs()
let last_updates = $("div[class$='col-CASES_LAST_UPDATE'],div[class$='col-CASES_LAST_UPDATE_DATE_ONLY']")
last_updates.each(function() {
let diff = dayjs( $(this).text() ).diff(now, 'day')
if ( diff <= -3 ) {
if ( diff <= -7 ) {
$(this).addClass("bg-light-red")
} else {
$(this).addClass("bg-washed-red")
}
}
})
}
// class="x-grid3-col-CASES_STATUS"
function colorize_cases_status() {
let WoC = $("div[class$='col-CASES_STATUS']:contains('Customer')")
let WoS = $("div[class$='col-CASES_STATUS']:contains('Support')")
let WoE = $("div[class$='col-CASES_STATUS']:contains('Engineering')")
let WoU = $("div[class$='col-CASES_STATUS']:contains('Upstream')")
let WoO = $("div[class$='col-CASES_STATUS']:contains('Operation')")
let New = $("div[class$='col-CASES_STATUS']:contains('New')")
WoC.addClass("bg-light-green")
WoS.addClass("bg-light-red")
WoE.addClass("bg-light-yellow")
WoU.addClass("bg-light-blue")
WoO.addClass("bg-light-blue")
New.addClass("bg-light-red")
}
function wait_for_el(selector, callback){
var poller1 = setInterval(function(){
$jObject = jQuery(selector);
if($jObject.length < 1){
return;
}
clearInterval(poller1);
callback($jObject)
},100);
}
if ( $(document).attr("title").match(/Case: \d+/) ) {
inject_css()
always_show_details()
style_description()
clear_comments()
move_sections()
set_comment_defaults()
move_comment_form()
}
else {
inject_css()
waitForKeyElements(".x-grid3-row", function() {
colorize_cases_last_update()
colorize_cases_status()
})
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment