diff options
author | Matěj Cepl <mcepl@redhat.com> | 2009-11-15 23:38:56 +0100 |
---|---|---|
committer | Matěj Cepl <mcepl@redhat.com> | 2009-11-15 23:38:56 +0100 |
commit | f6473374cf5984ebdb3e96edc1e176ae65bc2eac (patch) | |
tree | 851bcae1bcc7309d58b48c9d7bc1b7988a637e6f /bugzillaBugTriage.js | |
parent | 56c6054e53f51abe940561b49280feb569f8f846 (diff) | |
download | bugzilla-triage-f6473374cf5984ebdb3e96edc1e176ae65bc2eac.tar.gz |
We want to follow jetpack directory. Filtering out will be done before
merge to master.
Diffstat (limited to 'bugzillaBugTriage.js')
-rw-r--r-- | bugzillaBugTriage.js | 1315 |
1 files changed, 1315 insertions, 0 deletions
diff --git a/bugzillaBugTriage.js b/bugzillaBugTriage.js new file mode 100644 index 0000000..0d323e6 --- /dev/null +++ b/bugzillaBugTriage.js @@ -0,0 +1,1315 @@ +// Released under the MIT/X11 license +// http://www.opensource.org/licenses/mit-license.php + +// https://bugzilla.redhat.com/show_bug.cgi?id=451951 +// + +// EXAMPLE OF THE WORKING JETPACK FUNCTION!!! +//jetpack.future.import("pageMods"); + +//var callback = function(document) { +// jetpack.statusBar.append({ +// html: "BOOM<i>!</i>", +// width: 45, +// onReady: function(widget) { +// console.log("Boom!"); +// }, +// }); +//}; +//var options = {}; +//options.matches = [ +// "https://bugzilla.redhat.com/show_bug.cgi*", +// "https://bugzilla.redhat.com/process_bug.cgi"]; +//jetpack.pageMods.add(callback, options); + +// Interesting JEPs +// https://wiki.mozilla.org/Labs/Jetpack/JEP/10 -- clipboard access +// https://wiki.mozilla.org/Labs/Jetpack/JEP/17 -- page mods + +// ************* FUNCTIONS ******************** +/* EXTERNAL FUNCTIONS */ +/** + * split URI into array + * + * @param str string with the URL + * @return array with parsed URL + * + * parseUri 1.2.1 + * originally from http://blog.stevenlevithan.com/archives/parseuri + * (c) 2007 Steven Levithan <stevenlevithan.com> + * MIT License + */ +function parseUri (str) { + var o = parseUri.options, + m = o.parser[o.strictMode ? "strict" : "loose"].exec(str), + uri = {}, + i = 14; + + while (i--) { + uri[o.key[i]] = m[i] || ""; + } + + uri[o.q.name] = {}; + uri[o.key[12]].replace(o.q.parser, function ($0, $1, $2) { + if ($1) uri[o.q.name][$1] = $2; + }); + + return uri; +}; + +parseUri.options = { + strictMode: false, + key: ["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"], + q: { + name: "queryKey", + parser: /(?:^|&)([^&=]*)=?([^&]*)/g + }, + parser: { + strict: /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/, + loose: /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/ + } +}; + +/** + * Clean the string from spaces around + * + * @param string to be cleaned + * @return string which was cleaned + * + */ +function strip(str) { + return str.replace(/^\s*(.*)\s*$/,"$1"); +} + +/** + * Primitive version of sprintf + * @param string with the format of the result and + * @param list of parameters + * @return string with the format applied + * + * Call as + * format("And the %1 want to know whose %2 you %3", "papers", "shirt", "wear"); + * originally from + * http://www.sitepoint.com/blogs/2008/11/11/arguments-a-javascript-oddity/ + * FIXME needs testing and debugging + */ +function format(string) { + var args = arguments; + var pattern = new RegExp("%([1-" + arguments.length + "])", "g"); + return String(string).replace(pattern, function(match, index) { + return args[index]; + }); +} + +/** + * escape input string so that it could be used in URLs + * @param clearString + * @return string decoded so that it is safe for URLs + */ +function URLEncode (clearString) { + var output = ''; + var x = 0; + clearString = clearString.toString(); + var regex = /(^[a-zA-Z0-9_.]*)/; + while (x < clearString.length) { + var match = regex.exec(clearString.substr(x)); + if (match != null && match.length > 1 && match[1] != '') { + output += match[1]; + x += match[1].length; + } else { + if (clearString[x] == ' ') + output += '+'; + else { + var charCode = clearString.charCodeAt(x); + var hexVal = charCode.toString(16); + output += '%' + ( hexVal.length < 2 ? '0' : '' ) + hexVal.toUpperCase(); + } + x++; + } + } var output = ''; + var x = 0; + clearString = clearString.toString(); + var regex = /(^[a-zA-Z0-9_.]*)/; + while (x < clearString.length) { + var match = regex.exec(clearString.substr(x)); + if (match != null && match.length > 1 && match[1] != '') { + output += match[1]; + x += match[1].length; + } else { + if (clearString[x] == ' ') + output += '+'; + else { + var charCode = clearString.charCodeAt(x); + var hexVal = charCode.toString(16); + output += '%' + ( hexVal.length < 2 ? '0' : '' ) + hexVal.toUpperCase(); + } + x++; + } + } + return output; + + return output; +} + +/** + * 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']).test(chosingMark); + }); + }; + if (chosenPair.length > 0) { + return strip(chosenPair[0]['addr']).toLowerCase(); + } 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 i = 0; i < list.length; i++) { + // FIXME how to say hasAttribute in jQuery? + if(list[i].hasAttribute("value")) { + // FIXME getAttribute in jQuery + member = list[i].getAttribute("value"); + member = member.replace(/\s*(.*)\s*/,"$1"); + outL[outL.length] = member; + } + } + 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 + * + */ +// FIXME to-be-replaced by +// var contents = jetpack.clipboard.get(); +unsafeWindow.getClipboard = function() { + 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; +}; + + function getClipboardText() { + return unsafeWindow.getClipboard(); + } + +/** + * Compatibility layer for Firefox <3.1 which doesn't have native JSON support + * + * @param str string with the JSON data + * @return object + */ +//FIXME get rid of this ... user just has to have FF > 3.1 +function jsonParse(str) { + if (JSON) { + return JSON.parse(str); + } else { + return(eval('(' + str + ')')); + } +} + +/* Bugzilla functions.*/ + +/** + * add Fedora Bug zapper's signature to the comment of the current bug + */ +function addSignature(evt) { + var cmntText = document.getElementById("comment"); + if ((signatureFedoraString.length > 0) && (strip(cmntText.value).length > 0)) { + cmntText.value = strip(cmntText.value) + signatureFedoraString; + } +} + +/** + * Send mouse click to the specified element + * @param element where to send mouseclick to + * @return None + */ +function clickMouse(target) { + var localEvent = document.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(); + + inElem.normalize(); + + // getting name of the attachment + var bElem = inElem.getElementsByTagName("b")[0]; + name = strip(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 + // not sure whether the following is possible, otherwise + // I would have to get first span element + var spanElems = inElem.getElementsByClassName("bz_attach_extra_info")[0]; + var roundedText = spanElems.innerHTML; + + var stringArray = strip(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 the attachments table of the bug + * + * @return attachments table + */ +function getAttTable() { + var tempList = document.getElementById("attachment_table"); + return(tempList); +} + +/** + * 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); +} + +/* + * 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 + */ + +/** + * 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 + */ +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() { + var text = window.getSelection().toString(); + if (text.length < 1) { + text = getClipboardText(); + }; + if (text.length > 0) { + queryInNewTab(text, component); + } +} + +/** + * 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); + 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 + */ +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++; +} + +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 = document.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; + } + } +// tdElement.parentNode.insertBefore(tElem,tdElement.nextSibling); +// tdElement.parentNode.insertBefore(document.createElement("td"), +// tdElement.nextSibling); +} + +function addTextLink(row) { + var aList = row[row.length-1].getElementsByTagName("a"); + var curElem = aList[aList.length-1]; + var tElem = {}; + var t2Elem = {}; + + curElem.parentNode.appendChild(document.createTextNode(" ")); + t2Elem = document.createTextNode("Text"); + tElem = document.createElement("a"); + tElem.setAttribute("href",""); + tElem.addEventListener('click', + function(event) { + fixAttachById(row[1],"text/plain"); + }, + true); + tElem.appendChild(t2Elem); + curElem.parentNode.appendChild(document.createElement("br")); + curElem.parentNode.appendChild(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 = document.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 = document.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 strip(document.getElementById("component").value); +} + +/** + * Returns the product the bug belongs to + * + * @return string product the bug belongs to + */ +function getProduct() { + var productSelect = document.getElementById("product"); + 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 = document.getElementById("version"); + if (versionSelect) { + var index = versionSelect.selectedIndex; + return versionSelect.options[index].value; + } else { + return null; + } +} + +/** + * Returns owner of the bug. + * + * @return string with the email address of the assignee. + */ +function getAssignedTo() { + var assigneeEditContainer = document.getElementById("bz_assignee_edit_container").getElementsByClassName("fn")[0]; + return strip(assigneeEditContainer.textContent).toLowerCase(); +} + +/** + * Returns reporter of the bug. + * + * @return string with the email address of the reporter. + */ +function getReporter() { + var reportedSpanTag = document.getElementById("bz_show_bug_column_2").getElementsByClassName("fn")[0]; + return reportedSpanTag.textContent; +} + +/** + * Returns the number of the current bug + * + * @return int with the bug number + */ +function getBugNo() { + var title = strip(document.getElementById("title").getElementsByTagName("p")[0].innerHTML); + var bugNo = eval(title.split(" ")[1]); + return bugNo; +} + +/** + * Returns list of people getting CC of all bug messages. + * + * @return array with the all members of the CC list. + */ +function getCCList() { + var selectRef = document.getElementsByName("cc"); + if (selectRef.length>0) { + return valuesToList(selectRef[0]); + } else { + return []; + } +} + +/** + * 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() { + return filterByRegexp(AddrArray,component); +} + +/** + * Returns default assignee for the bug's component + * @return string with the default assignee for given component + */ +function getDefaultAssignee() { + return filterByRegexp(defAssigneeList,getComponent()); +} + +/** + * 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 = document.getElementById("cf_issuetracker"); + if (interestingElement) { + return strip(interestingElement.value); + } else { + return ""; + } +} + + +/** + * 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 + document.body.style.background = brandColor; + document.getElementById("titles").style.background = brandColor; + + // Make background-color of the body of bug salmon pink + // for security bugs. + if (hasKeyword("Security")) { + var divBody = document.getElementById("bugzilla-body"); + divBody.style.backgroundImage = "none"; + divBody.style.backgroundColor = SalmonPink; + } + + + // we should make visible whether maintCCAddr is in CCList + if (isInList(maintCCAddr, CCList)) { + var switchCCEdit=document.getElementById("cc_edit_area_showhide"); + //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 = document.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 = document.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 = strip(document.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 = document.getElementById("set_default_assignee"); + setDefaultAssigneeCheckbox.checked = false; + selectOption("bug_status", "ASSIGNED"); +} + +/** + * Set the bug to NEEDINFO state + * + * Working function. + * @return none + */ +function setNeedinfoReporter() { + var checkbox = document.getElementById("needinfo"); + 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 = document.getElementById("comment"); + + // 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 = document.getElementById("newcc"); + 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") { + document.getElementById("addselfcc").checked = true; + } else if (secondParameter == "NODEFAULTASSIGNEE") { + document.getElementById("set_default_assignee").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 = document.getElementById("external_bugs_table"); + var refs = externalRefs.getElementsByTagName("tr"); + // that's a bad id, if there is a one. + var inputBox = document.getElementById("inputbox"); + var externalBugID = 0; + var externalHost = ""; + var wholeURL = ""; + + // Fix missing ID on the external_id SELECT + document.getElementsByName("external_id")[0].id = "external_id"; + + if (inputBox.value.match(/^http.*/)) { + wholeURL = inputBox.value; + var IBURLArr = parseUri(wholeURL); + externalHost = IBURLArr.host; + externalBugID = parseInt(IBURLArr.queryKey["id"]); + inputBox.value = externalBugID; + var bugzillaName = getBugzillaName(externalHost); + selectOption("external_id", bugzillaName); + } else if (!isNaN(inputBox.value)) { + externalBugID = parseInt(inputBox.value); + var bugzillaID = document.getElementById("external_id").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 = document.getElementById("cc"); + selBox[myAddrIndex].selected = true; + document.getElementById("removecc").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 = document.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 = GM_getValue("BZpassword",""); + if (password == "") { + password = prompt("Enter your Bugzilla password",""); + GM_setValue("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 = document.getElementById("header"); + + var headerLiElements = divHeaderElement.getElementsByTagName("ul")[0].getElementsByTagName("li"); + var loginLIElement = headerLiElements[headerLiElements.length-1]; + var loginText = strip(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 GM_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 = document.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 = document.getElementById("comment"); + var brElement = document.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 = document.getElementById("newcommentprivacy"); + 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(document.createTextNode("\u00A0"),newButt); + } + // Add setting default assignee + var defAssignee = getDefaultAssignee(); + if ((defAssignee.length > 0) && (defAssignee != owner)) { + var divAssigned = document.getElementById("bz_assignee_edit_container"); + var divAssignedInput = document.getElementById("assigned_to"); + var divAssignedActiveCheckbox = document.getElementById("bz_assignee_edit_action"); + 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(document.createTextNode("\u00A0"),newButt); + } + var curComponentElement = document.getElementById("component"); + curComponentElement.addEventListener('change', + function(event) { + //FIXME We screw up default assignee value for unknown components + var assignee = getDefaultAssignee(); + if (assignee.length > 0) { + clickMouse(document.getElementById("bz_assignee_edit_action")); + document.getElementById("assigned_to").value = assignee; + document.getElementById("set_default_assignee").checked = false; + } + },false); +} + +// ****************** STATIC DATA ************************* + +var XMLRPCurl = "https://bugzilla.redhat.com/xmlrpc.cgi"; +// 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 = GM_getValue("JSONURL","http://mcepl.fedorapeople.org/scripts/BugZappers_data.json"); +var debug = GM_getValue("debug",false); +var reqCounter = 0; +var msgStrs = {}; + +var RHColor = "#9E292B"; +var FedoraColor = "#002867"; +var RawhideColor = "#007700"; // or "green" +var RHITColor = "#660066"; +var SalmonPink = "#FFE0B0"; + +// Initialize data from remote URL +var XMLHTTPRequestDone = false; +var hashBugzillaName = Array(); +var hashBugzillaWholeURL = Array(); +var defAssigneeList = Array(); +var signatureFedoraString = ""; +var queryButtonAvailable = false; +var AddrArray = Array(); +GM_xmlhttpRequest({ + method: 'GET', + url: jsonDataURL, + onload: function(response) { + var data = jsonParse(response.responseText); + 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']; + buildButtons(data['topRow'],data['bottomRow']); + if (signatureFedoraString.length > 0) { + console.logs("yes, add signature listener"); + // (or a form named "changeform") + document.forms[1].addEventListener("submit",addSignature,true); + } + + + } +}); +// ******************** MAIN ********************* + +function main(document) { + // FOR DEBUGGING ONLY!!! + if (debug) { + console.log("signatureFedoraString = " + signatureFedoraString); + var urlWarning = document.createElement("span"); + urlWarning.appendChild(document.createTextNode(jsonDataURL)); + urlWarning.style.fontSize = "x-small"; + var urlWarningParent = document.getElementById("bz_field_status"); + urlWarningParent.appendChild(urlWarning); + } + + // *** collect information about the bug + var bugNo = getBugNo(); + var reporter = getReporter(); + var owner = getAssignedTo(); + var CCList = getCCList(); + var product = getProduct(); + var version = getVersion(); + var issueTracker = getIssueTracker(); + var maintCCAddr = getCCMaintainer(); + var component = getComponent(); + + checkPrivateValues(); + + var login = getLogin(); + var password = GM_getValue("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); + } + + // ---------------------------------------------- + // fix attachments + var aTable = getAttTable(); + var badAttachments = getAttachments(aTable).filter(isOctetStream); + + if (badAttachments.length>0) { + var titleElement = $("bz_alias_short_desc_container"); + titleElement.style.backgroundColor = "olive"; + titleElement.appendChild(createFixAllButton(badAttachments)); + for(var i=0;i<badAttachments.length;i++) { + addTextLink(badAttachments[i]); + } + } + + var originalButton = document.getElementById("commit"); // source button to be copied from + originalButton.setAttribute("accesskey",'s'); + originalButton.setAttribute("value","Submit"); +} + +// @require jquery.rpc.js + +jetpack.future.import("pageMods"); +jetpack.tabs.focused.contentDocument.write("<script type='text/javascript'>$.getScript('http://mcepl.fedorapeople.org/scripts/jquery.rpc.js');</script>",function() { +console.log("jquery.rpc.js loaded"); +}); + +var options = {}; +options.matches = [ + "https://bugzilla.redhat.com/show_bug.cgi*", + "https://bugzilla.redhat.com/process_bug.cgi"]; +jetpack.pageMods.add(main, options); +jetpack.tabs.focused. +$('#header').css('backgroundColor','red') |