// Released under the MIT/X11 license
// http://www.opensource.org/licenses/mit-license.php
jetpack.future.import("pageMods");
jetpack.future.import("storage.simple");
jetpack.future.import("selection");
jetpack.future.import("clipboard");
var RHColor = "#9E292B";
var FedoraColor = "#002867";
var RawhideColor = "#007700"; // or "green"
var RHITColor = "#660066";
var SalmonPink = "#FFE0B0";
var ReporterColor = "#FFFFA6";
var XMLRPCurl = "https://bugzilla.redhat.com/xmlrpc.cgi";
var myConfig = jetpack.storage.simple;
var badMIMEArray = ["application/octet-stream","text/x-log"];
//==============================================================
// 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]+)\\).*$");
var inArray = ["application/octet-stream","text/x-log"];
// 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 topRow = {};
var bottomRow = {};
// Get JSON configuration data
$.getJSON(jsonDataURL, function (response) {
msgStrs = response.strings;
signatureFedoraString = response.signature;
hashBugzillaName = response.bugzillalabelNames;
hashBugzillaWholeURL = response.bugzillaIDURLs;
// [{'regexp to match component':'email address of an universal maintainer'}, ...]
AddrArray = response.CCmaintainer;
defAssigneeList = response.defaultAssignee;
queryButtonAvailable = response.queryButton;
chipIDsGroupings = response.chipIDsGroupings;
topRow = response.topRow;
bottomRow = response.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
*/
filterByRegexp = function(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
*/
valuesToList = function(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.
*/
isInList = function(mbr, list) {
return (list.indexOf(mbr) !== -1);
}
/**
* This function creates a new anchor element and uses location properties (inherent)
* to get the desired URL data. Some String operations are used (to normalize results
* across browsers).
* originally from http://snipplr.com/view.php?codeview&id=12659
*
* @param url String with URL
* @return object with parameters set
*
*/
function parseURL(url) {
var a = $('a',this.doc).get(0);
a.href = url;
return {
source: url,
protocol: a.protocol.replace(':',''),
host: a.hostname,
port: a.port,
query: a.search,
params: (function(){
var ret = {},
seg = a.search.replace(/^\?/,'').split('&'),
len = seg.length, i = 0, s;
for (;i<len;i++) {
if (!seg[i]) { continue; }
s = seg[i].split('=');
ret[s[0]] = s[1];
}
return ret;
})(),
file: (a.pathname.match(/\/([^\/?#]+)$/i) || [,''])[1],
hash: a.hash.replace('#',''),
path: a.pathname.replace(/^([^\/])/,'/$1'),
relative: (a.href.match(/tp:\/\/[^\/]+(.+)/) || [,''])[1],
segments: a.pathname.replace(/^\//,'').split('/')
};
}
/**
* 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));
};
/**
* Send mouse click to the specified element
* @param element where to send mouseclick to
* @return None
*/
bzPage.prototype.clickMouse = function(target) {
var localEvent = this.doc.get(0).createEvent("MouseEvents");
localEvent.initMouseEvent("click", true, true,
this.doc.defaultView,
0, 0, 0, 0, 0, false, false, false, false, 0, null);
$(target).get(0).dispatchEvent(localEvent);
}
/**
* Add new keyword among the keywords.
*
* @param str string with the new keyword
* @return none
*
* Checks for the existing keywords.
*/
bzPage.prototype.addKeyword = function (str) {
var kwd = $('#keywords',this.doc);
if (kwd.text().length == 0) {
kwd.text(str);
}else{
kwd.text(kwd.text() + ", " + str);
}
}
/* Bugzilla functions.*/
/**
* Set background color of all comments made by reporter in ReporterColor color
*
*/
bzPage.prototype.checkComments = function () {
var that = this;
$("#comments .bz_comment", this.doc).each(function (i) {
var email = $(".vcard a", this).text();
if (new RegExp(that.reporter).test(email)) {
$(this).css("background-color", ReporterColor);
}
});
};
/**
* 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 = this.checkChipStringFromID("1002",cardID);
if (cardIDArr.length > 0) {
cardIDStr = cardIDArr[0];
if (cardIDArr[1]) {
optionStr = cardIDArr[1];
outStr = this.groupIDs(driverStr,cardIDStr)+"/" + optionStr;
console.log("cardIDArr = " + cardIDArr.toSource() + ", outStr = "+outStr);
} else {
outStr = this.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 = this.groupIDs(cardIDArr[1],iLine);
} else {
outStr = iLine;
}
}
var whiteboardInput = $("#status_whiteboard",this.doc);
var oldWhiteboard = whiteboardInput.attr("value");
var attachedText = $.trim("card_"+outStr);
if (oldWhiteboard) {
attachedText += ", " + oldWhiteboard;
}
whiteboardInput.attr("value",attachedText);
$("#chipmagic", this.doc).css("display","none");
};
/**
* Generic function to add new button to the page.
* Actually copies new button from the old one (in order to have the same
* look-and-feel, etc.
* @param originalLocation object with the button to be copied from
* @param newId string with the id of the new button; has to be unique in
whole page
* @param newLabel string with the label which will be shown to user
* @param commentString string with comment to be added to the comment box
* @param nState string with the new state bug should switch to (see
* generalPurposeCureForAllDisease function for details)
* @param secPar string with second parameter for generalPurposeForAllDisease
* @param doSubmit bool optional whether the button should submit whole page
* (default true)
*
* @return none
*/
bzPage.prototype.addNewButton = function (originalLocation,newId,newLabel,
commentString,nState,secPar,doSubmit,after) {
var that = this;
var commStr = "";
if (doSubmit === null) { // missing optional argument
doSubmit = false;
}
if (after === null) { // missing optional argument
after = false;
}
if (msgStrs[commentString]) {
commStr = msgStrs[commentString];
}
var newButton = this.originalButton.clone(true).attr({
"id":newId,
"value":newLabel
}).click(function (evt) {
that.generalPurposeCureForAllDisease(commStr,nState, secPar);
});
newButton;
if (after) {
$(originalLocation, this.doc).after(newButton).after("\u00A0");
} else {
$(originalLocation, this.doc).before(newButton).before("\u00A0");
}
if (!doSubmit) {
newButton.get(0).setAttribute("type","button");
}
}
/**
* 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,paramList
* so that slow XMLHTTPRequest is done in advance.
*
* @return None
*/
bzPage.prototype.fillInChipMagic = function () {
var XorgLogURL = "";
var XorgLogAttID = "";
var XorgLogFound = false;
var attURL = "", interestingLine = "";
var interestingArray = [];
// Find out Xorg.0.log attachment URL
this.XorgLogAttList = this.attachments.filter(function (value, index, array) {
// Xorg.0.log must be text, otherwise we cannot parse it
return (/[xX].*log/.test(value[0]) && /text/.test(value[2]));
});
if (this.XorgLogAttList.length == 0) {
console.log("No Xorg.0.log attachments found.")
return;
}
var XorgLogAttID = this.XorgLogAttList[this.XorgLogAttListIndex][1];
attURL = "https://bugzilla.redhat.com/attachment.cgi?id="+XorgLogAttID;
that = this;
$.get(attURL,function (ret){
var interestingLineArr = ret.split("\n").filter(function (v,i,a) {
return ChipsetRE.test(v);
});
if (interestingLineArr.length >0) {
interestingArray = ChipsetRE.exec(interestingLineArr[0]);
interestingLine = $.trim(interestingArray[2].replace(/[\s"]+/g," "));
console.log("interestingArray = " + interestingArray.toSource() +
", interestingLine = " + interestingLine);
var whiteboardInput = $("#status_whiteboard",that.doc);
that.addNewButton(whiteboardInput,"chipmagic","Fill In",
"","CHIPMAGIC",
interestingLine+"\t"+interestingArray[1].toUpperCase(),
false,true);
}
});
this.XorgLogAttListIndex++;
};
/**
* Opens a new tab with a query for the given text in the selected component
* @param text to be searched for
* @param component string with the component name (maybe latter regexp?)
* @param product (optional) string with the product name
* @return None
*
* old
* long_desc=Xpress%20200&bug_status=NEW&bug_status=ASSIGNED
* new
* long_desc_type=substring&long_desc=Xpress%20200&bug_status=NEW&bug_status=ASSIGNED
*/
bzPage.prototype.queryInNewTab = function(text,component,product) {
// Optional parameter
if (product == null) {
product = "Fedora";
}
var url = "https://bugzilla.redhat.com/buglist.cgi?query_format=advanced";
if (product) {
url += "&product="+product;
}
if (component) {
url += "&component="+component;
}
if (text) {
url += "&field0-0-0=longdesc&type0-0-0=substring&value0-0-0="+text+
"&field0-0-1=attach_data.thedata&type0-0-1=substring&value0-0-1="+text;
}
jetpack.tabs.open(url);
}
/**
* Get the text to search for and prepare other things for the real executive
* function this.queryInNewTab, and run it.
*/
bzPage.prototype.queryForSelection = function() {
var text = $.trim(jetpack.selection.text);
if (text.length < 1) {
text = jetpack.clipboard.get();
};
if (text.length > 0) {
this.queryInNewTab(text, this.component);
}
}
/**
* 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 (inElem,idx) {
var MIMEtype = String();
var size = Number();
// 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:contains('Details')", inElem);
var id = parseInt(aHrefs.attr("href").replace(/^.*attachment.cgi\?id=/, ""),10);
//getting MIME type and size
var stringArray = $(".bz_attach_extra_info",inElem).text().
replace(/[\n ()]+/g," ").trim().split(", ");
size = parseInt(stringArray[0],10);
MIMEtype = stringArray[1].split(" ")[0];
return [attName,id,MIMEtype,size,inElem];
};
/**
* Select option with given label on the <SELECT> element with given id.
*
* Also execute change HTMLEvent, so that the form behaves accordingly.
*
* @param id
* @param label
* @return none
*/
bzPage.prototype.selectOption = function(id,label) {
var selectElement = $("#"+id,this.doc);
var theOption = $("option[value='"+label+"']",selectElement);
theOption.attr("selected","selected");
var intEvent = $(this.doc).get(0).createEvent("HTMLEvents");
intEvent.initEvent("change", true, true);
selectElement.get(0).dispatchEvent(intEvent);
}
/**
* 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 (RegExp(str).test(kwd));
}
/**
* Add accesskey to the particular element
*
* @param rootElement element to which the new text object will be attached
* @param beforeText text before the accesskey character
* @param accKey what will be the accesskey itself
* @param afterText text after the accesskey character
* @return modified element with the fixed accesskey
*
*/
bzPage.prototype.fixElement = function (rootElement,beforeText,accKey,afterText) {
elem = $(rootElement);
elem.attr("accesskey",accKey.toLowerCase());
elem.html(beforeText + "<b><u>" + accKey + "</u></b>" + afterText);
return elem;
}
/**
* Add XGL to the CC list
*
* @param evt event which made this function active
* @return none
*/
bzPage.prototype.changeOwner = function(newAssignee) {
/** Take care that when changing assignment of the bug,
* current owner is added to CC list.
* Switch off setting to the default assignee
*/
console.log("Changing owner of the bug to " + newAssignee);
if (!isInList(newAssignee, this.CCList)) {
$("#newcc",this.doc).text(newAssignee);
}
this.clickMouse($("#bz_assignee_edit_action",this.doc));
$("#set_default_assignee",this.doc).removeAttr("checked");
$("#assigned_to", this.doc).attr("value",newAssignee);
$("#setdefaultassigneebutton", this.doc).css("display","none");
}
/**
* Set the bug to NEEDINFO state
*
* Working function.
* @return none
*/
bzPage.prototype.setNeedinfoReporter = function() {
$("#needinfo",this.doc).click();
this.selectOption("needinfo_role", "reporter");
}
/**
* Add text to the comment.
* @param string2BAdded string to be added to the comment box
*
* @return none
*/
bzPage.prototype.addTextToComment = function(string2BAdded) {
var commentTextarea = $("#comment",this.doc);
// don't remove the current content of the comment box,
// just behave accordingly
if (commentTextarea.text().length > 0) {
commentTextarea.text(commentTextarea.text() + "\n\n");
}
commentTextarea.text(commentTextarea.text() + string2BAdded);
}
/**
* Return string with the ID for the external_id SELECT for
* external bugzilla
*
* @param URLhostname string hostname of the external bugzilla
* @return string with the string for the external_id SELECT
*/
bzPage.prototype.getBugzillaName = function(URLhostname) {
var bugzillaID = "";
if (hashBugzillaName[URLhostname]) {
bugzillaID = hashBugzillaName[URLhostname];
} else {
bugzillaID = "";
}
return bugzillaID;
}
/**
* Generate URL of the bug on remote bugzilla
* @param selectValue Number which is index of the bugzilla in hashBugzillaWholeURL
* @param bugID Number which is bug ID
* @return string with the URL
*/
bzPage.prototype.getWholeURL = function(selectValue,bugID) {
var returnURL = "";
if (hashBugzillaWholeURL[selectValue]) {
returnURL = hashBugzillaWholeURL[selectValue]+bugID;
} else {
returnURL = "";
}
return returnURL;
}
/**
* Sends XMLRPC request
*
* @param url string with URL of the XML-RPC interface
* @param data string with XML of the data to be sent
* @param method string -- either 'post' or 'get'
* @param callback function catching callback
*/
bzPage.prototype.sendRequest = function(url,data,method,callback) {
//$.rpc(url, dataType, onLoadCallback, version);
GM_xmlhttpRequest({
method: method,
url: url,
headers: {
'User-agent': 'Mozilla/4.0 (compatible) Greasemonkey fixAttType XMLRPC',
'Accept': 'application/atom+xml,application/xml,text/xml',
'Content-type': 'text/xml'
},
data: data,
onload: callback
});
}
/**
* Callback function for the XMLRPC request
*
* @param ret object with xmlhttprequest response
* with attributes:
* + status -- int return code
* + statusText
* + responseHeaders
* + responseText
*/
bzPage.prototype.callBack = function(ret) {
if (ret.status != 200) {
alert([ret.status,ret.statusText,ret.responseHeaders,
ret.responseText]);
}
if (--this.reqCounter <= 0) {
setTimeout(document.location.reload,1000);
}
}
/**
* The worker function -- call XMLRPC to fix MIME type of the
* particular attachment
*
* @param id integer with the attachment id to be fixed
* @param type string with the new MIME type, e.g. "text/plain"
*
updateAttachMimeType($data_ref, $username, $password)
Update the attachment mime type of an attachment. The first argument is a data hash containing information on the new MIME type and the attachment id that you want to act on.
$data_ref = {
"attach_id" => "<Attachment ID>",
# Attachment ID to perform MIME type change on.
"mime_type" => "<New MIME Type Value>",
# Legal MIME type value that you want to change the attachment to.
"nomail" => 0,
# OPTIONAL Flag that is either 1 or 0 if you want email to be sent or not for this change
};
*/
bzPage.prototype.fixAttachById = function(id,type) {
var ret = {};
var msg = new XMLRPCMessage("bugzilla.updateAttachMimeType");
msg.addParameter({'attach_id':id, 'mime_type':type});
msg.addParameter(login);
msg.addParameter(password);
try {
ret = sendRequest(XMLRPCurl,
msg.xml(),'post',callBack);
}
catch (e) {
alert([e,ret]);
}
this.reqCounter++;
}
bzPage.prototype.fixAllAttachments = function(list) {
var tmpElem = {};
for(var i=0;i<list.length;i++) {
tmpElem = list[i];
fixAttachById(tmpElem[1],"text/plain");
}
}
bzPage.prototype.createFixAllButton = function (list) {
var aElem = $("<a href=''></a>", this.doc).click(function() {
this.fixAllAttachments(list);
});
this.fixElement(aElem,"","F","ix all");
return aElem;
}
bzPage.prototype.getTextAllLink = function (table,list) {
var vAllElem = $("a[href*='action=enter']", $(table)).get();
}
bzPage.prototype.addTextLink = function (row) {
var aList = row[row.length-1].getElementsByTagName("a");
var curElem = aList[aList.length-1];
var tElem = {};
var t2Elem = {};
var that = this;
var tElem = $(" <a href=''>Text</a>",this.doc).click(function (event) {
that.fixAttachById(row[1],"text/plain");
});
$("a",row).after(tElem).after("<br/>");
}
bzPage.prototype.isOctetStream = function (element, index, array) {
return(inArray.indexOf(element[2]) != -1);
}
/**
* Add information about the upstream bug upstream, and closing it.
* @param evt event which called this handler
*
* @return none
*/
bzPage.prototype.addClosingUpstream = function() {
var refs = $("#external_bugs_table tr",this.doc);
// that's a bad id, if there is a one. :)
var inputBox = $("#inputbox",this.doc);
var externalBugID = 0;
var wholeURL = "";
// Fix missing ID on the external_id SELECT
$("select[name='external_id']:first",this.doc).attr("id","external_id");
if (inputBox.text().match(/^http.*/)) {
var IBURLArr = parseURL(inputBox.text());
console.log("IBURLArr = " + IBURLArr.toSource());
externalBugID = parseInt(IBURLArr.params["id"]);
inputBox.text(externalBugID);
var bugzillaName = getBugzillaName(IBURLArr.host);
this.selectOption("external_id", bugzillaName);
console.log("externalBugID = " + externalBugID);
} else if (!isNaN(inputBox.text())) {
externalBugID = parseInt(inputBox.text());
var bugzillaID = $("#external_id").text();
wholeURL = getWholeURL(bugzillaID,externalBugID);
} else {
// no inputBox.value -- maybe there is an external bug from
// the previous commit?
;
}
// It is not good to close bug as UPSTREAM, if there is no reference
// to the upstream bug.
if ((refs.length > 2) || (externalBugID > 0)) {
this.addTextToComment(msgStrs['sentUpstreamString'].replace("§§§",wholeURL));
this.selectOption("bug_status", "CLOSED");
this.selectOption("resolution", "UPSTREAM");
} else {
alert("No external bug specified among the External References!");
}
}
/** Insert a row of buttons before the marked element
*
* @param anchor element before which the row of buttons will be inserted
* @param array array of data for buttons to be generated
* @return none
*/
bzPage.prototype.generateToolBar = function(anchor,array) {
for (var i=0; i<array.length; i++) {
var butt = array[i];
this.addNewButton(anchor, butt['idx'],
butt['msg'], butt['string'], butt['state'], butt['parameter'],
butt['submit']);
}
}
/**
* Generalized function for all actions
*
* @param addString string to be added as new comment
* @param nextState string signifying next state of the bug (whatever is in Bugzilla +
"NEEDINFO" meaning NEEDINFO(Reporter))
* @param secondParameter string with label on the subbutton for reason
* of closing the bug
* @return none
*/
bzPage.prototype.generalPurposeCureForAllDisease = function
(addString,nextState,secondParameter) {
if (addString.length >0) {
this.addTextToComment(addString);
}
if (nextState == "CLOSED") {
if (secondParameter == "UPSTREAM") {
this.addClosingUpstream();
} else if (secondParameter.length > 0) {
this.selectOption("bug_status", nextState);
this.selectOption("resolution",secondParameter);
return 0;
} else {
throw("Missing resolution for CLOSED status.");
}
}
// Now closing bugs is done, what about the rest?
if (nextState == "NEEDINFO") {
this.setNeedinfoReporter();
} else if (nextState == "ADDKEYWORD") {
if (secondParameter.length == 0) {
throw "Keyword has to be defined";
}
this.addKeyword(secondParameter);
} else if (nextState == "ASSIGNED") {
if (!isInList(this.maintCCAddr, this.CCList)) {
$("#newcc",this.doc).text(this.maintCCAddr);
}
this.selectOption("bug_status", nextState);
} else if (nextState == "QUERYSEL") {
this.queryForSelection();
} else if (nextState == "SETDEFASS") {
if (secondParameter.length > 0) {
this.changeOwner(secondParameter);
}
} else if (nextState == "CHIPMAGIC") {
var splitArr = secondParameter.split("\t");
this.fillInWhiteBoard(splitArr[0],splitArr[1]);
} else if (nextState.length >0) {
this.selectOption("bug_status", nextState);
}
if (secondParameter == "ADDSELFCC") {
$("#addselfcc", this.doc).attr("checked","checked");
} else if (secondParameter == "NODEFAULTASSIGNEE") {
$("#set_default_assignee", this.doc).removeAttr("checked");
}
}
/**
* Main executable functioning actually building all buttons on the page --
* separated into function, so that
* it could be called from onload method of the 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 IBLast = $("#commit_top", this.doc);
this.addNewButton(IBLast,"changeOwnerbtn","reASSIGN",
"","ASSIGNED","NODEFAULTASSIGNEE");
// THE MAIN BUTTON ROWS
var commentBox = $("#comment", this.doc);
commentBox.before("<br>");
this.generateToolBar(commentBox.prev(),above);
this.generateToolBar(this.originalButton,below);
if (queryButtonAvailable) {
// Add query search button
// Apparently there is a bug in jQuery, we have to use plain DOM
//newPosition = $("#newcommentprivacy ~ br", this.doc);
newPosition = $(this.doc.get(0).querySelector("#newcommentprivacy ~ br"));
newPosition.css("border","solid blue");
this.addNewButton(newPosition,"newqueryintab","Query for string",
"","QUERYSEL","",false);
}
if ((chipIDsGroupings.length >0) && this.maintCCAddr == "xgl-maint@redhat.com") {
// Add find chip magic button
var whiteboard_string = $("#status_whiteboard", this.doc).attr("value");
if (whiteboard_string.indexOf("card_") == -1) {
this.fillInChipMagic();
}
}
// Add setting default assignee
console.log("defaultAssignee = " + this.defaultAssignee + ", owner = " + this.owner);
if ((this.defaultAssignee.length > 0) && (this.defaultAssignee != this.owner)) {
this.addNewButton($("#bz_assignee_edit_container", this.doc),
"setdefaultassigneebutton","Def. Assignee",
"","SETDEFASS",this.defaultAssignee,false,true);
}
};
///////////////////////////////////////////////////////////////////////////////
function bzPage(doc) {
this.doc = $(doc);
that = this;
this.originalButton = $("#commit", this.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 = $.makeArray($("#cc", this.doc).attr("value"));
this.owner = $("#bz_assignee_edit_container .fn:first", this.doc).text();
this.defaultAssignee = filterByRegexp(defAssigneeList, this.component).toLowerCase();
this.maintCCAddr = filterByRegexp(AddrArray,this.component).toLowerCase();
this.XorgLogAttList = [];
this.XorgLogAttListIndex = 0;
this.attachments = [];
this.reqCounter=0;
atts = $.makeArray($(("#attachment_table tr"),this.doc).slice(1,-1));
atts.forEach(function (val,idx,arr) {
that.attachments.push(that.parseAttachmentLine(val,idx));
});
var badAttachments = this.attachments.filter(function (att,idx,arr) {
return (badMIMEArray.indexOf(att[2]) != -1);
});
if (badAttachments.length > 0) {
console.log("we have " + badAttachments.length + " bad attachments.");
var titleElement = $(".bz_alias_short_desc_container:first").css("background-color",
"olive").append($(this.createFixAllButton(badAttachments)));
badAttachments.forEach(function (x) {
this.addTextLink(x);
});
}
// 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();
this.buildButtons(topRow,bottomRow);
var that = this;
$("#component",this.doc).change(function (){
that.changeOwner(that.maintCCAddr);
});
}
var callback = function (doc) {
var curPage = new bzPage(doc);
};
var options = {};
options.matches = [
"https://bugzilla.redhat.com/show_bug.cgi",
];
jetpack.pageMods.add(callback, options);