I've a VF Page which uses a Apex StandardSetController()
to display the list of a Standard Object Records(Case in my Page). The mini page layout which is a standard functionality from Salesforce has some CSS issues.
On Hover, the mini page layout appears as expected but the position is absolute. I've scroll-able view, so when I hover on records after scrolling(on those which were hidden previously), the mini page layout is shown at the absolute position and not at the current position.
I'm sure that it has nothing to do with the StandardSetController()
. Is there a CSS patch for this situation. Will it be a proper way to alter the Standard CSS since the classes and the CSS might be changed from the Salesforce side in a newer releases?
Attribution to: Vignesh Damodharan
Possible Suggestion/Solution #1
I've found the solution for this issue. The point is to give the popup an unique id. So we can't use the object reference id because it is a shared value on the page (like @JesseAltman said in his answer). Now we need to generate this ID manually and use an imitation of the popup. For that i will use an apex:variable
tag to generate ID if this form: hover123
:
Visualforce:
<apex:outputPanel style="width:300px;" layout="block">
<!-- Here defining a new variable for the fake id -->
<apex:variable value="{!0}" var="rowNumber" />
<apex:pageBlock mode="maindetail">
<apex:pageBlockTable value="{!accs}" var="a">
<apex:column value="{!a.name}"/>
<apex:column headerValue="Some header">
<a href="/{!a.test2__r.id}" id="hover{!rowNumber}"
position="relative"
onblur="LookupHoverDetail.getHover('hover{!rowNumber}').hide();"
onfocus="LookupHoverDetail.getHover('hover{!rowNumber}', '/{!a.test2__r.id}/m?retURL=%2F{!a.test2__r.id}&isAjaxRequest=1').show();"
onmouseout="LookupHoverDetail.getHover('hover{!rowNumber}').hide();"
onmouseover="LookupHoverDetail.getHover('hover{!rowNumber}', '/{!a.test2__r.id}/m?retURL=%2F{!a.test2__r.id}&isAjaxRequest=1').show();">
{!a.test2__r.name}
</a>
</apex:column>
<apex:column headerValue="1">
<!-- Increasing the value of the variable -->
<apex:variable var="rowNumber" value="{!rowNumber + 1}" />
</apex:column>
</apex:pageBlockTable>
</apex:pageBlock>
</apex:outputPanel>
Apex (here i have the same test2__c
reference in each account):
public with sharing class MyClass {
// Just a list with some accounts
public List<Account> accs { get; set; }
public MyClass() {
accs = [Select id, test2__c, test2__r.id, test2__r.name, Name
From Account
Limit 100];
}
}
This will looks like this:
Attribution to: Sergej Utko
Possible Suggestion/Solution #2
I came across this post trying to find a solution to the same issue, In my case i found that the popup was selecting the correct ID along the x axis but moving the position on the popup outside of the panel i wanted. So when i highlighted the linked item if it was say 800px on a scroller. It would move the popup to 800px outside the scroller.
This was the first issue I found. There were also ID issues along the X and Y for different commandLinks & when I reordered my page the popups would again be scrambled.
I worked out that the broken / buggy SalesForce code was within LookupHoverDetail.prototype.position. In here we were returning getObjX and getObjY wrongly.
So within my visualforce page I placed some overwriting code to replace the wrong possitions.
function getObjX(a) {
var left = 0;
while(a){
left += (a.offsetLeft - a.scrollLeft + a.clientLeft);
a = a.offsetParent;
}
return left;
}
function getObjY(a) {
var top = 0;
while(a){
top += (a.offsetTop - a.scrollTop + a.clientTop);
a = a.offsetParent;
}
return top;
}
Next I had to deal with the ID's being non-unique, I call this function after every Ajax event so that if I order the page, the Id's are to the correct links still. This function will execute at the same time as the others on load.
function fixSalesforce() {
$FFDC('.lineItem A').each(function(index){
var me = $FFDC(this);
var aId = me.attr('id');
if (aId != null){
var trId = me.closest('tr').attr('id');
if (aId.indexOf(trId) != 0){
var newId = trId + aId;
me.attr('id', newId);
me.attr('onmouseover', me.attr('onmouseover').replace( new RegExp(aId, 'g' ), newId));
me.attr('onmouseout', me.attr('onmouseout').replace( new RegExp(aId, 'g' ), newId));
me.attr('onfocus', me.attr('onfocus').replace( new RegExp(aId, 'g' ), newId));
me.attr('onblur', me.attr('onblur').replace( new RegExp(aId, 'g' ), newId));
}
}
});
}
The aim of the above function is to make the ID's unique by prefixing them with the row ID which I put on the TR.
{
<apex:variable value="{!0}" var="tRow" />
<apex:repeat var="tl"value="{!viewState.BankStatement.TransactionLineItems}"id="tRow1">
<tr id="tRow{!tRow}" class="lineItem{!IF(tl.isChecked,'selected','')}">
<apex:variable var="tRow"value="{!tRow+1}"/>
}
Within all CommandLinks I then placed onComplete="Refresh();"
This is a function that will call the fixSalesforce() function from earlier.
Attribution to: TimChadwick
Possible Suggestion/Solution #3
I've run into this issue before as well. It seems to be a combination of Javascript and CSS. Looking at their Javascript, this is the function that appears to be called
function LookupHoverDetail(a, b) {
this.id = a;
this.width = LookupHoverDetail.STANDARD_BUBBLE_WIDTH;
this.bubbleOffset = Sfdc.userAgent.isIE6 ? 5 : 14;
this.height = LookupHoverDetail.STANDARD_BUBBLE_HEIGHT;
this.hover = document.createElement("div");
this.hover.id = a + "Hover";
this.hover.className = "individualPalette lookupHoverDetail lookupHoverDetailLoading lookupHoverDetailOverridable";
this.hover.innerHTML = '<div class="topLeft"><div class="bPageBlock"><div class="pbBody">' + LC.getLabel("Global", "loading") + '<div><div class="pbFooter"><div class="bg"><div></div></div><div>';
document.body.appendChild(this.hover);
var c = this;
addEvent(this.hover, "mouseover", function () {
c.show()
}, true);
addEvent(this.hover, "mouseout", function () {
c.hide()
}, true);
this.hover = new iframeShim(this.hover);
this.originalClass = "";
this.fadingIn = this.fadingOut = null;
this.loaderURL = b;
this.loaded = false
}
LookupHoverDetail.STANDARD_BUBBLE_WIDTH = 302;
LookupHoverDetail.STANDARD_BUBBLE_HEIGHT = 262;
LookupHoverDetail.SHOW_DELAY = 800;
LookupHoverDetail.HIDE_DELAY = 250;
LookupHoverDetail.stopLoading = false;
LookupHoverDetail.hovers = {};
LookupHoverDetail.getHover = function (a, b) {
var c = window.Shepherd;
if (c && b) b = c.fixRetUrl(b);
if (LookupHoverDetail.hovers[a]) return LookupHoverDetail.hovers[a];
c = new LookupHoverDetail(a, b);
return LookupHoverDetail.hovers[a] = c
};
LookupHoverDetail.hideAllHovers = function () {
var a = LookupHoverDetail.hovers,
b;
for (b in a) a.hasOwnProperty(b) && a[b].hide()
};
LookupHoverDetail.prototype.show = function () {
if (this.fadingOut) {
clearTimeout(this.fadingOut);
this.fadingOut = null
} else {
var a = this;
if (!this.fadingIn) this.fadingIn = setTimeout(function () {
a.showNow()
}, LookupHoverDetail.SHOW_DELAY)
}
};
LookupHoverDetail.prototype.showNow = function () {
if (!this.loaded) if (this.loaderURL != null) {
var a = this;
Sfdc.Ajax.get(this.loaderURL, function (b) {
a.load(b)
}, {
failure: function (b) {
a.load(b)
}
})
} else return;
this.position();
this.hover.setStyle("visibility", "visible");
this.fadingIn = null
};
LookupHoverDetail.prototype.hide = function () {
if (this.fadingIn) {
clearTimeout(this.fadingIn);
this.fadingIn = null
} else {
var a = this;
this.fadingOut = setTimeout(function () {
a.hideNow()
}, LookupHoverDetail.HIDE_DELAY)
}
};
LookupHoverDetail.prototype.hideNow = function () {
this.hover.setStyle("visibility", "hidden");
this.fadingOut = null
};
LookupHoverDetail.prototype.load = function (a) {
this.hover.div.innerHTML = a;
Util.evalScriptsUnderElement(this.hover.div);
this.originalClass = this.hover.div.firstChild.className;
this.height = this.hover.div.offsetHeight;
delStyleClass(this.hover.div, "lookupHoverDetailLoading");
this.position();
this.loaded = true
};
LookupHoverDetail.prototype.position = function () {
var a = getElementByIdCS(this.id),
b = getObjX(a),
c = getObjY(a),
d = a.offsetWidth,
e = a.offsetHeight,
f = getScrollX(),
g = getScrollY(),
h = getWindowWidth(),
i = getWindowHeight();
a = this.originalClass + " ";
if (c + e + this.height < g + i) {
a += "top";
c += e
} else {
a += "bottom";
c -= this.height
}
if (b + d - this.bubbleOffset + this.width < f + h) {
a += "Left";
b = b + d / 2 - this.bubbleOffset
} else {
a += "Right";
b = b + d / 2 - this.width
}
this.hover.setStyle("left", b + "px");
this.hover.setStyle("top", c + "px");
this.hover.div.firstChild.className = a;
if (this.hover.div.firstChild) if (b = Util.hasStyleEndsWith(this.hover.div.firstChild, "Override")) {
delStyleClass(this.hover.div, "lookupHoverDetailOverridable");
delStyleClass(this.hover.div.firstChild, b);
addStyleClass(this.hover.div, b)
}
};
I would guess that Salesforce most likely uses the same ID for the same object referenced twice on a page (so if you have a lookup field to the same object twice on the page, they probably share the same ID), so when this LookupHoverDetail method is used, it looks for the first instance in the DOM which is at the top of the page.
To be completely honest with you, I am not sure how you can fix this. You will need to override Salesforce's included Javascript.
Attribution to: Jesse Altman
Possible Suggestion/Solution #4
For those who are still struck, once your page loads, have below function executed:check my blog
function modifyIDS(){
console.log('modifyIDS');
j$("a[id *='lookup']").each(function(index){
var newID = "referencedField"+index;
var elem = j$(this);
var fullHTML = elem[0].outerHTML;
var oldID = elem.attr('id');
console.log('modifyIDS2' +oldID);
var regex = new RegExp( oldID, 'g');
// console.log(fullHTML);
try{
elem[0].outerHTML = fullHTML.replace(regex,
newID);
}
catch(e){
console.log('error occured: '+e);
}
});
}
Attribution to: Sumit_Mishra
This content is remixed from stackoverflow or stackexchange. Please visit https://salesforce.stackexchange.com/questions/1707