-
-
Save zhouqt/a1ec7eb01e9b5814f121a27dd5f812e2 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==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