// Released under the MIT/X11 license
// http://www.opensource.org/licenses/mit-license.php
jetpack.future.import("pageMods");
jetpack.future.import("storage.simple");
// ************* FUNCTIONS ********************
/* EXTERNAL FUNCTIONS */
/**
* 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 = jetpack.tabs.focused.contentDocument.createElement('a');
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('/')
};
}
/**
* 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 = Array();
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 Object();
var strLength = new Object();
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.*/
/**
* add Fedora Bug zapper's signature to the comment of the current bug
*/
function addSignature(evt) {
var cmntText = $("#comment",document);
if ((signatureFedoraString.length > 0) && (trim(cmntText.value).length > 0)) {
cmntText.value = trim(cmntText.value) + signatureFedoraString;
}
}
/**
* Send mouse click to the specified element
* @param element where to send mouseclick to
* @return None
*/
function clickMouse(target) {
var localEvent = jetpack.tabs.focused.contentDocument.createEvent("MouseEvents");
localEvent.initMouseEvent("click", true, true, window,
0, 0, 0, 0, 0, false, false, false, false, 0, null);
target.dispatchEvent(localEvent);
}
/**
* Parse the row with the attachment
* @param <tr> 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 = String();
var MIMEtype = String();
var size = Number();
var id = Number();
// FIXME we should skip obsolete attachments
inElem.normalize();
// getting name of the attachment
var bElem = inElem.getElementsByTagName("b")[0];
name = trim(bElem.textContent);
// getting id
var aElem = inElem.getElementsByTagName("a")[0];
id = parseInt(aElem.getAttribute("href").replace(/^.*attachment.cgi\?id=/,""),10);
//getting MIME type and size
var spanElems = inElem.getElementsByClassName("bz_attach_extra_info")[0];
var roundedText = spanElems.innerHTML;
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]);
}
/**
* Get list of attachments to the bug
*
* @return array of attachments
*/
function getAttachments(attTable) {
var attList = Array();
var tempT = attTable.getElementsByTagName("tr");
if (tempT.length > 2) {
for (var i=1;i<tempT.length-1;i++) {
attList.push(parseAttachmentLine(tempT[i]));
}
}
return(attList);
}
function isOctetStream(element, index, array) {
var inArray = ["application/octet-stream","text/x-log"];
return(inArray.indexOf(element[2]) != -1);
}
function fixAttachments(){
var aTable = $("#attachment_table",document);
var attachmentsList = getAttachments(aTable);
var badAttachments = attachmentsList.filter(isOctetStream);
if (badAttachments.length>0) {
var titleElement = $(".bz_alias_short_desc_container:first",document);
titleElement.css("background-color","olive");
titleElement.append(createFixAllButton(badAttachments));
for(var i=0;i<badAttachments.length;i++) {
addTextLink(badAttachments[i]);
}
}
}
function groupIDs(manStr,cardStrID) {
// console.log("RegExpArr = " + chipIDsGroupings.toSource() + ", hledam = " + 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
*/
function checkChipStringFromID(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
*/
function fillInWhiteBoard(iLine,driverStr) {
var outStr = "";
var cardIDStr = "";
var cardIDArr = Array();
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 = $("#status_whiteboard",document);
var attachedText = trim("card_"+outStr);
if (whiteboardInput.value.length == 0) {
whiteboardInput.value = attachedText;
} else {
whiteboardInput.value += ", " + 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 fillInAddButton(interestLine,driverString) {
var newButt = originalButton.cloneNode(true);
var whiteboardInput = $("#status_whiteboard",document);
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(jetpack.tabs.focused.contentDocument.createTextNode("\u00A0"),newButt);
}
/**
* 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) {
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;
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.
* @param none
* @return none
*/
function fillInChipMagic() {
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 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 queryForSelection(component) {
var text = window.getSelection().toString();
if (text.length < 1) {
text = getClipboardText();
};
if (text.length > 0) {
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 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 callBack(ret) {
if (ret.status != 200) {
alert([ret.status,ret.statusText,ret.responseHeaders,
ret.responseText]);
}
if (--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"
*
*/
function fixAttachById(id,type) {
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) {
alert([e,ret]);
}
reqCounter++;
}
/**
* Callback function for "Fix all attachments" button
* @param list Array of
* @return none
*/
function fixAllAttachments(list) {
var tmpElem = {};
for(var i=0;i<list.length;i++) {
tmpElem = list[i];
fixAttachById(tmpElem[1],"text/plain");
}
}
function createFixAllButton(list) {
var aElem = jetpack.tabs.focused.contentDocument.createElement("a");
aElem.setAttribute("href","");
aElem.addEventListener('click',
function(event) {fixAllAttachments(list);},
true);
fixElement(aElem,"","F","ix all");
return aElem;
}
function getTextAllLink(table,list) {
var AList = table.getElementsByTagName("a");
var tElem = {};
var t2Elem = {};
var aElem = {};
var hStr = "";
var vAllElem = {};
for(var i=0;i<AList.length;i++) {
tElem = AList[i];
if (tElem.hasAttribute("href")) {
hStr = tElem.getAttribute("href");
} else {
hStr = "";
}
if(hStr.indexOf("action=enter") != -1) {
vAllElem = tElem;
}
}
}
function addTextLink(row) {
var aList = row[row.length-1].getElementsByTagName("a");
var curElem = aList[aList.length-1];
var tElem = {};
var t2Elem = {};
tElem = $(" <a href=''>Text</a>").bind("click",
function(event) {
fixAttachById(row[1],"text/plain");
});
tElem.appendChild(t2Elem);
$(curElem).parent().append("<br>");
$(curElem).parent().append(tElem);
}
function isOctetStream(element, index, array) {
var inArray = ["application/octet-stream","text/x-log"];
return(inArray.indexOf(element[2]) != -1);
}
//===========================
/**
* 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 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 <SELECT> element with given id.
*
* Also execute change HTMLEvent, so that the form behaves accordingly.
*
* @param id
* @param label
* @return none
*/
function selectOption(id,label) {
var selectElement = jetpack.tabs.focused.contentDocument.getElementById(id);
var values = selectElement.options;
for (var i = 0; i < values.length; i++) {
values[i].normalize();
if (values[i].text.search(label) != -1) {
values[i].selected = true;
var intEvent = jetpack.tabs.focused.contentDocument.createEvent("HTMLEvents");
intEvent.initEvent("change", true, true);
selectElement.dispatchEvent(intEvent);
break;
}
}
}
/**
* Returns the component of the bug
*
* @return string component of the bug
*/
function getComponent() {
return $.trim($("#component",document).attr("value"));
}
/**
* Returns the product the bug belongs to
*
* @return string product the bug belongs to
*/
function getProduct() {
var productSelect = $("#product",document);
var index = productSelect.selectedIndex;
return productSelect.options[index].value;
}
/**
* Returns the version of product the bug belongs to
*
* @return string revision of the product the bug belongs to
*/
function getVersion() {
var versionSelect = $("#version",document);
if (versionSelect) {
var index = versionSelect.selectedIndex;
return versionSelect.options[index].value;
} else {
return null;
}
}
/**
* Returns the number of the current bug
*
* @return int with the bug number
*/
function getBugNo() {
var title = $.trim($("#title > p:first",document).html());
return eval(title.split(" ")[1]);
}
/**
* Returns an email address for collective maintainers
* who should be on the CC of the bug.
*
* @return string email address to be on CC list.
*/
function getCCMaintainer(addrs) {
return filterByRegexp(addrs,getComponent()).toLowerCase();
}
/**
* Returns default assignee for the bug's component
* @return string with the default assignee for given component
*/
function getDefaultAssignee() {
return filterByRegexp(defAssigneeList,getComponent()).toLowerCase();
}
/**
* Get Issuetracker string from the bug page
* @return string issuetracker numbers or empty string (either because we have no IT
* or because it is not a RHEL bug).
*/
function getIssueTracker() {
var interestingElement = $("#cf_issuetracker",document);
if (interestingElement) {
return trim(interestingElement.value);
} else {
return "";
}
}
/**
* Is this bug Xorg bug?
* @return boolean
*/
function isXorgBug() {
return maintCCAddr == "xgl-maint@redhat.com";
}
/**
* Is this bug RHEL bug?
* @return boolean
*/
function isRHELBug() {
return getProduct().search(/Red Hat Enterprise Linux/) != -1;
}
/**
* 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
*
*/
function fixElement(rootElement,beforeText,accKey,afterText) {
rootElement.setAttribute("accesskey",accKey.toLowerCase());
rootElement.innerHTML = beforeText + "<b><u>" + accKey + "</u></b>" + afterText;
return rootElement;
}
/**
* 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
*/
function setBranding(brand,version,its) {
var brandColor = "";
if (brand.search(/Red Hat Enterprise Linux/) != -1) {
if (its.length > 0) {
brandColor = RHITColor;
} else {
brandColor = RHColor;
}
} else if (brand.search(/Fedora/) != -1) {
if (version.search(/rawhide/i) != -1) {
brandColor = RawhideColor;
} else {
brandColor = FedoraColor;
}
}
// Comment each of the following lines to get only partial branding
jetpack.tabs.focused.contentDocument.body.style.background = brandColor;
$("#titles",document).style.background = brandColor;
// Make background-color of the body of bug salmon pink
// for security bugs.
if (hasKeyword("Security")) {
var divBody = $("#bugzilla-body",document);
divBody.style.backgroundImage = "none";
divBody.style.backgroundColor = SalmonPink;
}
// we should make visible whether maintCCAddr is in CCList
if (isInList(maintCCAddr, CCList)) {
var switchCCEdit=$("#cc_edit_area_showhide",document);
//switchCCEdit.textContent = "*"+switchCCEdit.textContent;
switchCCEdit.style.color = "navy";
switchCCEdit.style.fontWeight = "bolder";
switchCCEdit.style.textDecoration = "underline";
}
}
/**
* 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
*/
function addNewButton(originalLocation,newId,newLabel,commentString,nState,secPar,doSubmit) {
if (doSubmit === null) { // missing optional argument
doSubmit = true;
}
var newButton = originalButton.cloneNode(true);
if (!doSubmit) {
newButton.setAttribute("type","button");
}
newButton.id=newId;
newButton.setAttribute("value",newLabel);
var commStr = "";
if (msgStrs[commentString]) {
commStr = msgStrs[commentString];
}
newButton.addEventListener('click',function (evt) {
generalPurposeCureForAllDisease(commStr, nState, secPar);
},true);
var textNode = jetpack.tabs.focused.contentDocument.createTextNode("\u00A0");
originalLocation.parentNode.insertBefore(textNode,originalLocation);
originalLocation.parentNode.insertBefore(newButton,textNode);
}
/**
* Add new keyword among the keywords.
*
* @param str string with the new keyword
* @return none
*
* Checks for the existing keywords.
*/
function addKeyword(str) {
var kwd = jetpack.tabs.focused.contentDocument.getElementById('keywords');
if (kwd.value.length == 0) {
kwd.value = str;
}else{
kwd.value = kwd.value + ", " + str;
}
}
/**
* Check for the presence of a keyword
*
* @param str string with the keyword
* @return Boolean
*
*/
function hasKeyword(str) {
var kwd = trim(jetpack.tabs.focused.contentDocument.getElementById('keywords').value);
return (RegExp(str).test(kwd));
}
/**
* Add XGL to the CC list
*
* @param evt event which made this function active
* @return none
*/
function changeOwnerHandler(evt) {
/** Take care that when changing assignment of the bug,
* current owner is added to CC list.
* Switch off setting to the default assignee
*/
if (!isInList(maintCCAddr, CCList)) {
addToCC(maintCCAddr);
}
var setDefaultAssigneeCheckbox = $("#set_default_assignee",document);
setDefaultAssigneeCheckbox.checked = false;
selectOption("bug_status", "ASSIGNED");
}
/**
* Set the bug to NEEDINFO state
*
* Working function.
* @return none
*/
function setNeedinfoReporter() {
var checkbox = $("#needinfo",document);
checkbox.click();
selectOption("needinfo_role", "reporter");
}
/**
* Add text to the comment.
* @param string2BAdded string to be added to the comment box
*
* @return none
*/
function addTextToComment(string2BAdded) {
var commentTextarea = $("#comment",document);
// don't remove the current content of the comment box,
// just behave accordingly
if (commentTextarea.value.length > 0) {
commentTextarea.value += "\n\n";
}
commentTextarea.value += string2BAdded;
}
/**
* add address to CC of this bug
*
* @param address string address to be added
* @return none
*/
function addToCC(address) {
var sel = $("#newcc",document);
sel.value = address;
}
/**
* 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
*/
function generalPurposeCureForAllDisease(addString,nextState,secondParameter) {
if (addString.length >0) {
addTextToComment(addString);
}
if (nextState == "CLOSED") {
if (secondParameter == "UPSTREAM") {
addClosingUpstream();
} else if (secondParameter.length > 0) {
selectOption("bug_status", nextState);
selectOption("resolution",secondParameter);
return 0;
} else {
throw("Missing resolution for CLOSED status.");
}
}
// Now closing bugs is done, what about the rest?
if (nextState == "NEEDINFO") {
setNeedinfoReporter();
} else if (nextState == "ADDKEYWORD") {
if (secondParameter.length == 0) {
throw "Keyword has to be defined";
}
addKeyword(secondParameter);
} else if (nextState == "ASSIGNED") {
if (!isInList(maintCCAddr, CCList)) {
addToCC(maintCCAddr);
}
selectOption("bug_status", nextState);
} else if (nextState.length >0) {
selectOption("bug_status", nextState);
}
if (secondParameter == "ADDSELFCC") {
$("#addselfcc",document).checked = true;
} else if (secondParameter == "NODEFAULTASSIGNEE") {
$("#set_default_assignee",document).checked = false;
}
}
/**
* 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
*/
function getBugzillaName(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
*/
function getWholeURL(selectValue,bugID) {
var returnURL = "";
if (hashBugzillaWholeURL[selectValue]) {
returnURL = hashBugzillaWholeURL[selectValue]+bugID;
} else {
returnURL = "";
}
return returnURL;
}
/**
* Add information about the upstream bug upstream, and closing it.
* @param evt event which called this handler
*
* @return none
*/
function addClosingUpstream() {
var externalRefs = $("#external_bugs_table",document);
var refs = externalRefs.getElementsByTagName("tr");
// that's a bad id, if there is a one.
var inputBox = $("#inputbox",document);
var externalBugID = 0;
var wholeURL = "";
// Fix missing ID on the external_id SELECT
jetpack.tabs.focused.contentDocument.getElementsByName("external_id")[0].id = "external_id";
if (inputBox.value.match(/^http.*/)) {
wholeURL = inputBox.value;
var IBURLArr = parseURL(wholeURL);
console.log("IBURLArr = " + IBURLArr.toSource());
externalBugID = parseInt(IBURLArr.params["id"]);
inputBox.value = externalBugID;
var bugzillaName = getBugzillaName(IBURLArr.host);
selectOption("external_id", bugzillaName);
console.log("externalBugID = " + externalBugID);
} else if (!isNaN(inputBox.value)) {
externalBugID = parseInt(inputBox.value);
var bugzillaID = $("#external_id",document).value;
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)) {
addTextToComment(msgStrs['sentUpstreamString'].replace("§§§",wholeURL));
selectOption("bug_status", "CLOSED");
selectOption("resolution", "UPSTREAM");
} else {
alert("No external bug specified among the External References!");
}
}
/**
* Currently we don't use this function
* @param evt event send from DOM (not used)
* @return none
*/
function swapXGLMainToCCListHandler(evt) {
/** Remove mcepl@redhat.com from CC list and put there
* xgl-maint@redhat.com
*/
myAddrIndex = CCList.indexOf(login);
if (!isInList(maintCCAddr, CCList)) {
addToCC(maintCCAddr);
}
if (isInList(login, CCList)) {
var selBox = $("#cc",document);
selBox[myAddrIndex].selected = true;
$("#removecc",document).checked = true;
}
evt.stopPropagation();
evt.preventDefault();
}
/**
* Go through all <a> elements in the page and fix those starting with #
* to point to the real bug, not to process.cgi page.
* @param bugNo
*/
function fixAllHrefs(bugNo) {
var AList = jetpack.tabs.focused.contentDocument.getElementsByTagName("a");
var curA;
var hrefStr = "";
var reProcess = RegExp("");
for(var i=0;i<AList.length;i++) {
curA = AList[i];
if (curA.hasAttribute("href")) {
hrefStr = curA.getAttribute("href");
if (reProcess.test(hrefStr)) {
hrefStr = "show_bug.cgi?id="+bugNo.toString()+hrefStr;
curA.setAttribute("href",hrefStr);
}
}
}
}
/** Insert 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
*/
function generateToolBar(anchor,array) {
for (var i=0; i<array.length; i++) {
var butt = array[i];
addNewButton(anchor, butt['idx'],
butt['msg'], butt['string'], butt['state'], butt['parameter'], butt['submit']);
}
}
/**
* make sure that prefs.js contain password for bugzilla
* @return None
*/
function checkPrivateValues() {
var password = "";
if (myStorage.BZpassword) {
password = myStorage.BZpassword;
}
if (password == "") {
password = prompt("Enter your Bugzilla password","");
myStorage.BZpassword = password;
}
}
/**
* There is a login printed on each page, go get it.
* @return string with the login
*/
function getLogin() {
var tmpElement = {};
var tmpText = "";
var divHeaderElement = $("#header",document);
var headerLiElements = divHeaderElement.getElementsByTagName("ul")[0].getElementsByTagName("li");
var loginLIElement = headerLiElements[headerLiElements.length-1];
var loginText = trim(loginLIElement.lastChild.textContent);
return loginText;
}
/**
* 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
*/
function buildButtons(above,below) {
// TODO: I don't need this now and it isn't compatible with new style
// generalPurposeCureForAllDisease driving addNewButton.
//// Just for fixing wrong CC list
//if (isInList(login,CCList) && !isInList(maintCCAddr,CCList)) {
// addNewButton(IBList[1],"swapXGLMainToCCList","Swap -maint to CC",
// swapXGLMainToCCListHandler);
//}
//----------------------------------------------
//Generate a list of <input> elements in the page
var IBList = [];
var IBRawList = jetpack.tabs.focused.contentDocument.getElementsByTagName("input");
for (var i=0;i<IBRawList.length;i++) {
if ((IBRawList[i].hasAttribute("type")) &&
(IBRawList[i].getAttribute("type")=="submit")) {
IBList = IBList.concat(IBRawList[i]);
}
}
// BUTTONS ON THE BOTTOM OF THE FORM
// Create a new SUBMIT button adding current owner of the bug to
// the CC list
var IBLast = IBList[IBList.length-4];
addNewButton(IBLast,"changeOwnerbtn","reASSIGN",
"","ASSIGNED","NODEFAULTASSIGNEE");
// BUTTONS ABOVE THE COMMENT BOX
var textCommentElement = $("#comment",document);
var brElement = jetpack.tabs.focused.contentDocument.createElement("br");
textCommentElement.parentNode.insertBefore(brElement,textCommentElement);
//var brElement = findNextSiblingByTagName(textCommentElement,"BR",false);
var insertAfterElement = brElement;
generateToolBar(insertAfterElement,above);
// BUTTONS BELOW THE COMMENT BOX
generateToolBar(originalButton,below);
// FIXME put this somehow into addNewButton and generalPurposeCureForAllDisease
// framework
if (queryButtonAvailable){
// Add query search button
var privateCheckbox = $("#newcommentprivacy",document);
var newPosition = privateCheckbox.nextSibling.nextSibling.nextSibling;
var newButt = originalButton.cloneNode(true);
newButt.setAttribute("id","newqueryintab");
newButt.setAttribute("value","Query for string");
newButt.addEventListener('click',function (evt) {
queryForSelection();
},true);
newButt.setAttribute("type","button");
newPosition.parentNode.insertBefore(newButt,newPosition);
newPosition.parentNode.insertBefore(jetpack.tabs.focused.contentDocument.createTextNode("\u00A0"),newButt);
}
if ((chipIDsGroupings.length >0) && isXorgBug()) {
// Add find chip magic button
var whiteboardInput = $("#status_whiteboard",document);
if (whiteboardInput.value.search(/card_/) == -1) {
fillInChipMagic();
}
}
// Add setting default assignee
var defAssignee = getDefaultAssignee();
if ((defAssignee.length > 0) && (defAssignee != owner)) {
var divAssigned = $("#bz_assignee_edit_container",document);
var divAssignedInput = $("#assigned_to",document);
var divAssignedActiveCheckbox = $("#bz_assignee_edit_action",document);
newButt = originalButton.cloneNode(true);
newButt.setAttribute("id","setdefaultassigneebutton");
newButt.setAttribute("value","Def. Assignee");
newButt.addEventListener('click',function (evt) {
if (defAssignee.length > 0) {
clickMouse(divAssignedActiveCheckbox);
divAssignedInput.value = defAssignee;
}
},true);
newButt.setAttribute("type","button");
divAssigned.appendChild(newButt);
newButt.parentNode.insertBefore(jetpack.tabs.focused.contentDocument.createTextNode("\u00A0"),newButt);
}
var curComponentElement = $("#component",document);
curComponentElement.addEventListener('change',
function(event) {
//FIXME We screw up default assignee value for unknown components
var assignee = getDefaultAssignee();
if (assignee.length > 0) {
clickMouse($("#bz_assignee_edit_action",document));
$("#assigned_to",document).value = assignee;
$("#set_default_assignee",document).checked = false;
}
},false);
}
// ****************** 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 = 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);
}
});
// ******************** MAIN *********************
function main() {
var hashBugzillaName = Array();
var hashBugzillaWholeURL = Array();
var defAssigneeList = Array();
var signatureFedoraString = "";
// TODO we should have an array SpecialFlags instead of multiple Boolean variables
var queryButtonAvailable = false;
var chipIDsGroupings = Array();
var AddrArray = Array();
// Initialize data from remote URL
var XMLHttpRequestDone = false;
var XorgLogAttList = Array();
var 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",document).append("<span inline='font-size:x-small'>"+jsonDataURL+"</span>");
}
// *** collect information about the bug
// var bugNo = getBugNo();
console.log("BBB");
var bugNo = $("#title > p:first",document).text();
console.log("BBB");
console.log(bugNo);
var reporter = $('#bz_show_bug_column_2 > .fn:first',document).text();
var owner = $.trim($("#bz_assignee_edit_container > .fn:first",document).text()).toLowerCase();
var CCList = $("select[name*='cc']:first > *[value]",document);
console.log(typeof(CCList));
var product = getProduct();
var version = getVersion();
var issueTracker = getIssueTracker();
var maintCCAddr = getCCMaintainer(AddrArray);
var component = getComponent();
checkPrivateValues();
var login = getLogin();
var password = myStorage.BZpassword;
//*** set the main environment
setBranding(product,version,issueTracker);
// fix process.cgi HREFs so that to avoid confusion on IRC
if (document.location.href.search(/process.cgi/) != -1) {
fixAllHrefs(bugNo);
}
fixAttachments();
var originalButton = document.getElementById("commit"); // source button to be copied from
originalButton.setAttribute("accesskey",'s');
originalButton.setAttribute("value","Submit");
}
// https://bugzilla.redhat.com/show_bug.cgi?id=451951
//
// Interesting JEPs
// https://wiki.mozilla.org/Labs/Jetpack/JEP/10 -- clipboard access
// https://wiki.mozilla.org/Labs/Jetpack/JEP/17 -- page mods
var callback = function(document) {
jetpack.statusBar.append({
onReady: function(widget) {
console.log("Boom!");
main();
},
});
};
var options = {};
options.matches = [
"https://bugzilla.redhat.com/show_bug.cgi*",
"https://bugzilla.redhat.com/process_bug.cgi"];
jetpack.pageMods.add(callback, options);
Chyba: document is not defined
Zdrojový soubor: file:///home/matej/Dokumenty/projekty/triage/jetpack/bugzillaBugTriage.js
Řádek: 1369