// Released under the MIT/X11 license
// http://www.opensource.org/licenses/mit-license.php
jetpack.future.import("pageMods");
jetpack.future.import("storage.simple");
var RHColor = "#9E292B";
var FedoraColor = "#002867";
var RawhideColor = "#007700"; // or "green"
var RHITColor = "#660066";
var SalmonPink = "#FFE0B0";
var ReporterColorHex = "#FFFFA6";
var XMLRPCurl = "https://bugzilla.redhat.com/xmlrpc.cgi";
var myConfig = jetpack.storage.simple;
//==============================================================
// CONFIGURE: The easiest method how to set up the configuration
// value is to uncomment the following line with proper URL as
// the second parameter. Then reload the bug page and comment out
// again.
// myConfig.JSONURL = "URL-somewhere-with-your-JSON";
var jsonDataURL = myConfig.JSONURL ? myConfig.JSONURL :
"http://mcepl.fedorapeople.org/scripts/BugZappers_data.json";
var PCIIDsURL = "http://mcepl.fedorapeople.org/scripts/drm_pciids.json";
//var debug = GM_getValue("debug",false);
var reqCounter = 0;
var msgStrs = {};
var CommentRe = new RegExp("^\\s*#");
var BlankLineRe = new RegExp("^\\s*$");
var ChipsetRE = new RegExp("^\\(--\\) ([A-Za-z]+)\\([0-9]?\\): Chipset: (.*)$");
var ATIgetIDRE = new RegExp("^.*\\(ChipID = 0x([0-9a-fA-F]+)\\).*$");
// For identification of graphics card
var manuChipStrs = [
["ATI Radeon", "ATI", "1002"],
["ATI Mobility Radeon", "ATI", "1002"],
["Intel Corporation", "INTEL", "8086"],
["NVIDIA", "NV", "10de"]
];
var backTranslateManufacturerPCIID = [{
regexp: "ATI Technologies Inc",
addr: "1002"
}, {
regexp: "Intel Corporation",
addr: "8086"
}, {
regexp: "nVidia Corporation",
addr: "10de"
}];
// Initialize data from remote URL
var XMLHTTPRequestDone = false;
var hashBugzillaName = [];
var hashBugzillaWholeURL = [];
var defAssigneeList = [];
var signatureFedoraString = "";
// TODO we should have an array SpecialFlags instead of multiple Boolean variables
var queryButtonAvailable = false;
var chipIDsGroupings = [];
var AddrArray = [];
var PCI_ID_Array = [];
var XorgLogAttList = [];
var XorgLogAttListIndex = 0;
// Get JSON configuration data
$.getJSON(jsonDataURL, function (response) {
var data = response;
msgStrs = data.strings;
signatureFedoraString = data.signature;
hashBugzillaName = data.bugzillalabelNames;
hashBugzillaWholeURL = data.bugzillaIDURLs;
// [{'regexp to match component':'email address of an universal maintainer'}, ...]
AddrArray = data.CCmaintainer;
defAssigneeList = data.defaultAssignee;
queryButtonAvailable = data.queryButton;
chipIDsGroupings = data.chipIDsGroupings;
// TODO buildButtons(data.topRow,data.bottomRow);
});
// Get card translation table
$.getJSON(PCIIDsURL,
function (response) {
PCI_ID_Array = response;
});
//==============================================================
/**
* select element of the array where regexp in the first element matches second parameter
* of this function
* @param list array with regexps and return values
* @param chosingMark string by which the element of array is to be matched
* @return string chosen element
*/
function filterByRegexp(list, chosingMark) {
var chosenPair = [];
if (list.length > 0) {
chosenPair = list.filter(
function (pair) {
return new RegExp(pair.regexp, "i").test(chosingMark);
});
}
if (chosenPair.length > 0) {
return $.trim(chosenPair[0].addr);
} else {
return "";
}
}
/**
* Converts attributes value of the given list of elements to the
* Javascript list.
* @param list array of elements
* @return array of values
*/
function valuesToList(list) {
var outL = [];
list.forEach(function (e, i, a) {
if (e.hasAttribute("value")) {
outL.push(e.getAttribute("value").trim());
}
});
return outL;
}
/**
* Check whether an item is member of the list. Idea is just to
* make long if commands slightly more readable.
*
* @param mbr string to be searched in the list
* @param list list
* @return position of the string in the list, or -1 if none found.
*/
function isInList(mbr, list) {
return (list.indexOf(mbr) !== -1);
}
///////////////////////////////////////////////////////////////////////////////
function bzPage(doc) {
this.doc = $(doc);
var bugNoTitle = $.trim($("#title > p:first", this.doc).text());
this.bugNo = new RegExp("[0-9]+").exec(bugNoTitle)[0];
this.reporter = $("#bz_show_bug_column_2 > table .vcard:first > a",
this.doc).attr("title");
this.product = $("#product option:selected:first", this.doc).text();
this.component = $("#component option:selected:first", this.doc).text();
this.version = $("#version option:selected:first", this.doc).text();
this.its = $.trim($("#cf_issuetracker", this.doc).text());
this.CCList = $("#cc", this.doc).attr("value");
this.defaultAssignee = filterByRegexp(defAssigneeList, this.component).toLowerCase();
this.maintCCAddr = filterByRegexp(AddrArray,this.component).toLowerCase();
this.attachments = $("#attachment_table tr",
this.doc).slice(1,-1).map(this.parseAttachmentLine);
this.originalButton = $("#commit", this.doc).get(0);
// Take care of signature for Fedora bugzappers
if (signatureFedoraString.length > 0) {
// (or a form named "changeform")
$("form:nth-child(2)", this.doc).submit(function () {
var cmntText = $("#comment", this.doc);
if ((signatureFedoraString.length > 0) &&
($.trim(cmntText.text()).length > 0)) {
cmntText.text($.trim(cmntText.text()) + signatureFedoraString);
}
});
}
this.setBranding();
this.checkComments();
}
/**
* Check for the presence of a keyword
*
* @param str string with the keyword
* @return Boolean
*
*/
bzPage.prototype.hasKeyword = function (str) {
var kwd = $.trim($('#keywords', this.doc).text());
return (new RegExp(str).test(kwd));
};
/* Bugzilla functions.*/
/**
* Set background color of all comments made by reporter in ReporterColorHex color
*
*/
bzPage.prototype.checkComments = function () {
var reporter = this.reporter;
$("#comments .bz_comment", this.doc).each(function (i) {
var email = $(".vcard a", this).text();
if (new RegExp(reporter).test(email)) {
$(this).css("background-color", ReporterColorHex);
}
});
};
/**
* Set branding colours to easily distinguish between Fedora and RHEL bugs
*
* @param brand string with product of the current bug
* @param version string with the version of the bug
* @param its string with the IsueTracker numbers
* @return none
*
*/
bzPage.prototype.setBranding = function () {
var brandColor = "";
if (new RegExp("Red Hat Enterprise Linux").test(this.product)) {
if (this.its.length > 0) {
brandColor = RHITColor;
} else {
brandColor = RHColor;
}
} else if (new RegExp("Fedora").test(this.product)) {
if (new RegExp("rawhide", "i").test(this.version)) {
brandColor = RawhideColor;
} else {
brandColor = FedoraColor;
}
}
// Comment each of the following lines to get only partial branding
$("body", this.doc).css("background", brandColor);
$("#titles", this.doc).css("background", brandColor);
// Make background-color of the body of bug salmon pink
// for security bugs.
if (this.hasKeyword("Security")) {
$("#bugzilla-body", this.doc).css({
'background-image' : 'none',
'background-color' : SalmonPink
});
}
// we should make visible whether maintCCAddr is in CCList
if (isInList(this.maintCCAddr, this.CCList)) {
$("#cc_edit_area_showhide", this.doc).
css({ "color": "navy",
"font-weight": "bolder",
"text-decoration": "underline"});
}
};
bzPage.prototype.groupIDs = function (manStr,cardStrID) {
var outStr = filterByRegexp(chipIDsGroupings,manStr+","+cardStrID);
if (outStr.length == 0) {
outStr = "UNGROUPED_" + manStr+"/"+cardStrID;
}
return outStr;
};
/**
* Given PCI IDs for manufacturer and card ID return chipset string
*
* @param manufacturerNo string with manufacturer PCI ID
* @param cardNo string with card PCI ID
*
* @return array with chip string and optinoal variants
*/
bzPage.prototype.checkChipStringFromID = function (manufacturerNo,cardNo) {
console.log("This is the card ID: " + cardNo + " manufactured by " + manufacturerNo);
var soughtID = (manufacturerNo+","+cardNo).toUpperCase();
var outList = PCI_ID_Array[soughtID];
console.log("nalezeno = " + outList.toSource());
if (outList) {
return outList;
} else {
return "";
}
};
/**
* Given line to be parsed, find out which chipset it is and fill in the whiteboard
*
* @param iLine string with the whole unparsed "interesting line"
* @param driverStr string with the driver name
* @return None
*/
bzPage.prototype.fillInWhiteBoard = function (iLine,driverStr) {
var outStr = "";
var cardIDStr = "";
var cardIDArr = [];
console.log("driverStr = " + driverStr);
console.log("iLine: " + iLine);
chipSwitchboard:
if (driverStr == "RADEON") {
var cardID = iLine.replace(ATIgetIDRE,"$1");
cardIDArr = checkChipStringFromID("1002",cardID);
if (cardIDArr.length > 0) {
cardIDStr = cardIDArr[0];
if (cardIDArr[1]) {
optionStr = cardIDArr[1];
outStr = groupIDs(driverStr,cardIDStr)+"/" + optionStr;
console.log("cardIDArr = " + cardIDArr.toSource() + ", outStr = "+outStr);
} else {
outStr = groupIDs(driverStr,cardIDStr);
optionStr = "";
}
console.log("found IDs: " + cardIDStr + "," + optionStr);
} else {
outStr = "**** FULLSTRING: " + iLine;
}
} else {
// Intel Corporation, NVIDIA
cardIDArr = manuChipStrs.filter(function (el, ind, arr) {
return RegExp(el[0],"i").test(iLine);
});
console.log("cardIDArr = " + cardIDArr.toSource());
if (cardIDArr && (cardIDArr.length > 0)) {
cardIDArr = cardIDArr[0];
} else {
outStr = iLine;
break chipSwitchboard;
}
// cardIDArr [0] = RE, [1] = ("RADEON","INTEL","NOUVEAU"), [2] = manu PCIID
iLine = trim(iLine.replace(RegExp(cardIDArr[0],"i"),""));
// FIXME is this necessary? Let's try without it
// outStr = iLine.replace(/^\W*(\w*).*$/,"$1");
// nVidia developers opted-out from grouping
if (driverStr == "INTEL") {
outStr = groupIDs(cardIDArr[1],iLine);
} else {
outStr = iLine;
}
}
console.log("result = " + outStr);
var whiteboardInput = document.getElementById("status_whiteboard");
var attachedText = trim("card_"+outStr);
if (whiteboardInput.value.length == 0) {
whiteboardInput.value = attachedText;
} else {
whiteboardInput.value += ", " + attachedText;
}
};
//
bzPage.prototype.fillInAddButton = function (interestLine,driverString) {
var newButt = originalButton.cloneNode(true);
var whiteboardInput = document.getElementById("status_whiteboard");
newButt.setAttribute("id","chipmagic");
newButt.setAttribute("value","Fill In");
newButt.addEventListener('click',function (evt) {
fillInWhiteBoard(interestLine,driverString);
},true);
newButt.setAttribute("type","button");
whiteboardInput.parentNode.appendChild(newButt);
whiteboardInput.parentNode.insertBefore(document.createTextNode("\u00A0"),newButt);
};
/**
* Recursive function to run Get attached Xorg.0.log, parse it and find the value of chip
* @return None
*
*/
bzPage.prototype.fillInChipMagicProcessAtts = function (ret) {
if (ret) {
if (ret.status != 200) {
alert([ret.status,ret.statusText,ret.responseHeaders,
ret.responseText]);
throw "XMLHTTPRequest got return code " + ret.status;
}
console.log('fetched ' + ret.finalUrl);
var interestingLineArr = ret.responseText.split("\n").filter(function (v,i,a) {
return ChipsetRE.test(v);
});
console.log("interestingLineArr = " + interestingLineArr.toSource());
if (interestingLineArr.length >0) {
// Process and exit
// .replace(ChipsetRE,"$1\t$2").split("\t")
var interestingArray = ChipsetRE.exec(interestingLineArr[0]);
console.log("interesting array = " + interestingArray.toSource());
interestingLine = trim(interestingArray[2].replace(/[\s"]+/g," "));
console.log("interesting line = " + interestingLine);
fillInAddButton(interestingLine,interestingArray[1].toUpperCase());
console.log("XMLHTTPRequest done!");
return;
}
}
if (XorgLogAttList[XorgLogAttListIndex]) {
var XorgLogAttID = XorgLogAttList[XorgLogAttListIndex][1];
var attURL = "https://bugzilla.redhat.com/attachment.cgi?id="+XorgLogAttID;
GM_xmlhttpRequest({
method: 'GET',
url: attURL,
headers: {
'User-agent': 'Mozilla/4.0 (compatible) Greasemonkey getXorgLog',
'Accept': 'text/plain',
'Content-type': 'text/xml'
},
onload:fillInChipMagicProcessAtts
});
XorgLogAttListIndex++;
} else {
console.log("No more Xorg.0.log attachments!");
}
};
/**
* Get attached Xorg.0.log, parse it and find the value of chip.
* Does not fill the whiteboard itself, just adds button to do so,
* so that slow XMLHTTPRequest is done in advance.
*
* @return None
*/
bzPage.prototype.fillInChipMagic = function () {
var XorgLogURL = "";
var XorgLogAttID = "";
var XorgLogFound = false;
// Find out Xorg.0.log attachment URL
XorgLogAttList = this.attachments.filter(function (value, index, array) {
// Xorg.0.log must be text, otherwise we cannot parse it
return (RegExp("[xX].*log").test(value[0]) && /text/.test(value[2]));
});
console.log("XorgLogAttList = " + XorgLogAttList.toSource());
if (XorgLogAttList.length == 0) {
console.log("No Xorg.0.log attachments found.")
return;
}
fillInChipMagicProcessAtts();
};
/**
* Parse the row with the attachment
*
* @param <tr> DOM element to be parsed
* @return array with string name of the attachment,
integer its id number,
string of MIME type,
integer of size in kilobytes,
and the whole element itself
*/
bzPage.prototype.parseAttachmentLine = function (index,inElem) {
var MIMEtype = String();
var size = Number();
inElem.normalize();
// Skip over obsolete attachments
if ($(".bz_obsolete",inElem).length>0) {
return;
}
// getting name of the attachment
var attName = $.trim($("b:first", inElem).text());
// getting id
var aHrefs = $("a", inElem);
console.log("aHrefs = " + aHrefs.html());
var id = parseInt(aHrefs.attr("href").replace(/^.*attachment.cgi\?id=/, ""),10);
console.log("id = " + id);
//getting MIME type and size
var stringArray = $(".bz_attach_extra_info >*:first",inElem).text().
replace(/[\n ()]+/g," ").trim().split(", ");
size = parseInt(stringArray[0],10);
MIMEtype = stringArray[1];
return([attName,id,MIMEtype,size,inElem]);
};
/**
* Main executable functioning actually building all buttons on the page --
* separated into function, so that
* it could be called from onload method of the GM_XMLHTTPRequest.
*
* @param jsonList Array created from JSON
* @return none
*/
bzPage.prototype.buildButtons = function (above,below) {
//Generate a list of <input> elements in the page
var IBList = $("input[name*='submit']", this.doc);
var IBLast = IBList.get(IBList.length-4);
addNewButton(IBLast,"changeOwnerbtn","reASSIGN",
"","ASSIGNED","NODEFAULTASSIGNEE");
// BUTTONS ABOVE THE COMMENT BOX
var insAElem = $("<br>");
$("#comment", this.doc).before(insAElem);
generateToolBar(insAElem,above);
// BUTTONS BELOW THE COMMENT BOX
generateToolBar(this.originalButton,below);
// FIXME put this somehow into addNewButton and generalPurposeCureForAllDisease
// framework
if (queryButtonAvailable){
// Add query search button
var newPosition = $("#newcommentprivacy", this.doc).siblings("eq(3)");
var newButt = originalButton.clone(true).attr({
"id":"newqueryintab",
"value":"Query for string",
"type":"button"
}).click(function (evt) {
queryForSelection();
}).prependTo(newPosition).before("\u00A0");
}
if ((chipIDsGroupings.length >0) && this.maintCCAddr == "xgl-maint@redhat.com") {
// Add find chip magic button
if (!$("#status_whiteboard:contains('card_')", this.doc)) {
this.fillInChipMagic(); //FIXME missing!!!
}
}
// Add setting default assignee
if ((this.defAssignee.length > 0) && (this.defAssignee != owner)) {
var divAssigned = $("#bz_assignee_edit_container", this.doc);
var divAssignedInput = $("#assigned_to", this.doc);
var divAssignedActiveCheckbox = $("#bz_assignee_edit_action");
newButt = originalButton.clone(true).
attr({"id":"setdefaultassigneebutton",
"value":"Def. Assignee",
"type":"button"
}).click(function (evt) {
if (defAssignee.length > 0) {
clickMouse(divAssignedActiveCheckbox);
$(divAssignedInput,this.doc).text(defAssignee);
}
}); //FIXME SHOULD CONTINUE WHERE I ENDED HERE!
divAssigned.appendChild(newButt);
newButt.parentNode.insertBefore(document.createTextNode("\u00A0"),newButt);
}
$("component").change(
function (event) {
//FIXME We screw up default assignee value for unknown components
var assignee = this.defAssignee;
// FIXME tohlenějak rozesraný Ježe.
if (assignee.length > 0) {
clickMouse(document.getElementById("bz_assignee_edit_action"));
$.ID("assigned_to").value = assignee;
document.getElementById("set_default_assignee").checked = false;
}
});
};
var callback = function (doc) {
var curPage = new bzPage(doc);
};
var options = {};
options.matches = [
"https://bugzilla.redhat.com/show_bug.cgi*",
"https://bugzilla.redhat.com/process_bug.cgi"
];
jetpack.pageMods.add(callback, options);