// Released under the MIT/X11 license
// http://www.opensource.org/licenses/mit-license.php
jetpack.future.import("pageMods");
jetpack.future.import("storage.simple");
// Static values
// ****************** STATIC DATA *************************
var XMLRPCurl = "https://bugzilla.redhat.com/xmlrpc.cgi";
var myStorage = 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.
//GM_setValue("JSONURL","URL-somewhere-with-your-JSON");
var jsonDataURL = "";
myStorage.JSONURL = "http://barstool.build.redhat.com/~mcepl/RH_Data.json";
if (myStorage.JSONURL) {
jsonDataURL = myStorage.JSONURL;
}
if (!jsonDataURL) {
jsonDataURL = "http://mcepl.fedorapeople.org/scripts/BugZappers_data.json";
}
console.log("jsonDataURL = " + jsonDataURL);
var PCIIDsURL = "http://mcepl.fedorapeople.org/scripts/drm_pciids.json";
//var debug = GM_getValue("debug",false);
var debug = true;
var reqCounter = 0;
var msgStrs = {};
var RHColor = "#9E292B";
var FedoraColor = "#002867";
var RawhideColor = "#007700"; // or "green"
var RHITColor = "#660066";
var SalmonPink = "#FFE0B0";
var CommentRe = RegExp("^\\s*#");
var BlankLineRe = RegExp("^\\s*$");
var ChipsetRE = RegExp("^\\(--\\) ([A-Za-z]+)\\([0-9]?\\): Chipset: (.*)$");
var ATIgetIDRE = RegExp("^.*\\(ChipID = 0x([0-9a-fA-F]+)\\).*$");
var PCI_ID_Array = [];
// 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"
}];
// Get card translation table
XMLHttpRequest({
// anything called inside of this Request cannot have variables set in MAIN
method: 'GET',
url: PCIIDsURL,
onload: function(response) {
PCI_ID_Array = JSON.parse(response.responseText);
}
});
// ************* FUNCTIONS ********************
/**
* Clean the string from spaces around
*
* @param string to be cleaned
* @return string which was cleaned
*
*/
function trim(str,cleanRE) {
var re = RegExp("^\\s*(.*)\\s*$");
if (cleanRE) {
re = RegExp(cleanRE);
}
return str.replace(re,"$1");
}
/**
* 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 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 = [];
var member = "";
for (var element in list) {
if (element.hasAttribute("value")) {
outL[outL.length] = $.trim(element.getAttribute("value"));
}
}
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);
}
/**
* returns content of the system clipboard
* @return string with the content of the clipboard or "" if empty.
* originally from
* https://developer.mozilla.org/en/Using_the_Clipboard
*
*/
// TODO to-be-replaced by
// var contents = jetpack.clipboard.get();
function getClipboardText() {
this.netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
var clip = Components.classes["@mozilla.org/widget/clipboard;1"].getService(Components.interfaces.nsIClipboard);
if (!clip) return(false);
;
var trans = Components.classes["@mozilla.org/widget/transferable;1"].createInstance(Components.interfaces.nsITransferable);
if (!trans) return(false);
trans.addDataFlavor("text/unicode");
clip.getData(trans, clip.kGlobalClipboard);
var str = new {};
var strLength = new {};
trans.getTransferData("text/unicode", str, strLength);
if (str) {
str = str.value.QueryInterface(Components.interfaces.nsISupportsString);
}
if (str) {
pastetext = str.data.substring(0, strLength.value / 2);
}
return pastetext;
};
/* Bugzilla functions.*/
function bzPage(doc) {
this.document = $(doc);
this.hashBugzillaName = [];
this.hashBugzillaWholeURL = [];
this.defAssigneeList = [];
this.signatureFedoraString = "";
// TODO we should have an array SpecialFlags instead of multiple Boolean variables
this.queryButtonAvailable = false;
this.chipIDsGroupings = [];
this.AddrArray = [];
// Initialize data from remote URL
this.XMLHttpRequestDone = false;
this.XorgLogAttList = [];
this.XorgLogAttListIndex = 0;
// Get JSON configuration data
XMLHttpRequest({
// anything called inside of this Request cannot have variables set in MAIN
method: 'GET',
url: jsonDataURL,
onload: function(response) {
var data = JSON.parse(response.responseText);
msgStrs = data['strings'];
signatureFedoraString = data['signature'];
hashBugzillaName = data['bugzillalabelNames'];
hashBugzillaWholeURL = data['bugzillaIDURLs'];
AddrArray = data['CCmaintainer'];
defAssigneeList = data['defaultAssignee'];
queryButtonAvailable = data['queryButton'];
chipIDsGroupings = data['chipIDsGroupings'];
buildButtons(data['topRow'],data['bottomRow']);
if (signatureFedoraString.length > 0) {
// (or a form named "changeform")
document.forms[1].addEventListener("submit",addSignature,true);
}
}
});
// FOR DEBUGGING ONLY!!!
if (debug) {
//console.log("signatureFedoraString = " + signatureFedoraString);
$("#bz_field_status",this.document).append(""+jsonDataURL+"");
}
// *** collect information about the bug
// var bugNo = getBugNo();
console.log("BBB");
var bugNo = $("#title > p:first",this.document).text();
console.log("BBB");
console.log(bugNo);
this.reporter = $('#bz_show_bug_column_2 > .fn:first',this.document).text();
this.owner = $.trim($("#bz_assignee_edit_container > .fn:first",this.document).text()).toLowerCase();
this.CCList = $("select[name*='cc']:first > *[value]",this.document);
console.log(typeof(this.CCList));
this.product = this.getProduct();
this.version = this.getVersion();
this.issueTracker = this.getIssueTracker();
this.maintCCAddr = this.getCCMaintainer(AddrArray);
this.component = this.getComponent();
this.checkPrivateValues();
this.login = this.getLogin();
this.password = myStorage.BZpassword;
//*** set the main environment
this.setBranding(product,version,issueTracker);
// fix process.cgi HREFs so that to avoid confusion on IRC
if (this.document.location.href.search(/process.cgi/) != -1) {
this.fixAllHrefs(bugNo);
}
this.fixAttachments();
this.originalButton = this.document("#commit"); // source button to be copied from
this.originalButton.attr("accesskey",'s');
this.originalButton.attr("value","Submit");
}
/**
* 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 bzPage.prototype.parseURL(url) {
var a = $('',this.document).get(0);
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 (var i=0;i 0) &&
($.trim(cmntText.value).length > 0)) {
cmntText.value = $.trim(cmntText.value) + this.signatureFedoraString;
}
}
/**
* Get list of attachments to the bug
*
* @return array of attachments
*/
function bzPage.prototype.fixAttachments(){
/**
* Parse the row with the attachment
* @param
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
*/
function parseAttachmentLine(inElem) {
var name = "";
var MIMEtype = "";
var size = Number();
var id = Number();
// FIXME we should skip obsolete attachments
inElem.normalize();
// getting name of the attachment
var bElem = $("b:first",inElem);
name = $.trim(bElem.text());
// getting id
id = parseInt($("a:first",inElem).attr("href").replace(/^.*attachment.cgi\?id=/,""),10);
//getting MIME type and size
var roundedText = $(".bz_attach_extra_info:first",inElem).html();
var stringArray = $.trim(roundedText.replace(/^\s*\((.*)\s*KB,\s*$/,"$1"));
size = parseInt(stringArray,10);
MIMEtype = roundedText.split("\n")[2].replace(/^\s*(.*)\)\s*$/,"$1");
return([name,id,MIMEtype,size,inElem]);
}
function getAttachments(attTable) {
var attList = [];
var tempT = $("tr",attTable).get();
if (tempT.length > 2) {
for (var i=1;i0) {
var titleElement = $(".bz_alias_short_desc_container:first",this.document);
titleElement.css("background-color","olive");
titleElement.append(createFixAllButton(badAttachments));
for(var i=0;i 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 = $("#status_whiteboard",this.document);
var attachedText = $.trim("card_"+outStr);
if (whiteboardInput.val().length == 0) {
whiteboardInput.val(attachedText);
} else {
whiteboardInput.val(whiteboardInput.val()+", " + attachedText);
}
}
/**
* Insert "Fill In" button to the status whiteboard
* @param interestLine string with the interesting part of the Chipset: line
* @param driverString string with name of the driver ("INTEL", "RADEON", "NOUVEAU",
* etc.)
* @return none
*/
function bzPage.prototype.fillInAddButton(interestLine,driverString) {
var newButt = $(this.originalButton).clone();
var whiteboardInput = $("#status_whiteboard",this.document);
newButt.attr("id","chipmagic");
newButt.attr("value","Fill In");
newButt.attr("type","button");
newButt.click(function (evt) {
this.fillInWhiteBoard(interestLine,driverString);
});
whiteboardInput.after(newButt);
whiteboardInput.after("\u00A0");
}
/**
* 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.
* @param none
* @return none
*/
function bzPage.prototype.fillInChipMagic() {
/**
* Recursive function to run Get attached Xorg.0.log, parse it and find the value of chip
* @return None
*/
function fillInChipMagicProcessAtts(ret) {
if (ret) {
if (ret.status != 200) {
jetpack.notifications.show([ret.status,ret.statusText,ret.responseHeaders,
ret.responseText].toSource());
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;
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!");
}
}
var XorgLogURL = "";
var XorgLogAttID = "";
var XorgLogFound = false;
// Find out Xorg.0.log attachment URL
XorgLogAttList = attachmentsList.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();
}
/**
* 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
*/
function bzPage.prototype.queryInNewTab(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 += "&long_desc_type=substring&long_desc="+ text.replace(" ","%20");
}
console.log("queryInNewTab: url = " + url);
window.open(url);
}
function bzPage.prototype.queryForSelection(component) {
var text = window.getSelection().to"";
if (text.length < 1) {
text = getClipboardText();
};
if (text.length > 0) {
this.queryInNewTab(text, getComponent());
}
}
/**
* 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
*/
function bzPage.prototype.sendRequest(url,data,method,callback) {
//$.rpc(url, dataType, onLoadCallback, version);
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
*/
function bzPage.prototype.callBack(ret) {
if (ret.status != 200) {
jetpack.notifications.show([ret.status,ret.statusText,ret.responseHeaders,
ret.responseText].toSource());
}
if (--reqCounter <= 0) {
setTimeout("document.location.reload()",1000);
}
}
/**
* Callback function for "Fix all attachments" button
* @param list Array of
* @return none
*/
function bzPage.prototype.fixAllAttachments(list) {
var tmpElem = {};
/**
* 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"
*
*/
function fixAttachById(id,type) {
// FIXME XMLRPCMessage
var msg = new XMLRPCMessage("bugzilla.updateAttachMimeType");
msg.addParameter({'attach_id':id, 'mime_type':type});
msg.addParameter(login);
msg.addParameter(password);
try {
var ret = sendRequest(XMLRPCurl,
msg.xml(),'post',callBack);
}
catch (e) {
jetpack.notifications.show([e,ret].toSource());
}
reqCounter++;
}
for(var i=0;i");
aElem.click(function(event) {
fixAllAttachments(list);
});
fixElement(aElem,"","F","ix all");
return aElem;
}
function bzPage.prototype.addTextLink(row) {
var aList = row[row.length-1].getElementsByTagName("a");
var curElem = aList[aList.length-1];
var tElem = {};
var t2Elem = {};
tElem = $(" Text").bind("click",
function(event) {
fixAttachById(row[1],"text/plain");
});
tElem.appendChild(t2Elem);
$(curElem).parent().append(" ");
$(curElem).parent().append(tElem);
}
//===========================
/**
* Find the next (or previous) sibling element of given tagName
* starting from given element.
*
* @param startElement element from which to start searching
* @param tagName string tagName of the searched for element (case insensitive)
* @param forward boolean optional should we search forward or backward?
* @return element of the given tagName or null
*/
function bzPage.prototype.findNextSiblingByTagName(startElement,tagName,forward) {
if (forward === null) { // missing optional argument
forward = true;
}
var tempElement = startElement;
tagName = tagName.toUpperCase();
while (tempElement && tempElement.tagName != tagName) {
if (forward) {
tempElement = tempElement.nextSibling;
} else {
tempElement = tempElement.previousSibling;
}
}
return tempElement;
}
/**
* Select option with given label on the