aboutsummaryrefslogtreecommitdiffstats
path: root/bugzillaBugTriage.js
diff options
context:
space:
mode:
authorMatěj Cepl <mcepl@redhat.com>2009-11-15 23:38:56 +0100
committerMatěj Cepl <mcepl@redhat.com>2009-11-15 23:38:56 +0100
commitf6473374cf5984ebdb3e96edc1e176ae65bc2eac (patch)
tree851bcae1bcc7309d58b48c9d7bc1b7988a637e6f /bugzillaBugTriage.js
parent56c6054e53f51abe940561b49280feb569f8f846 (diff)
downloadbugzilla-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.js1315
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("&nbsp;")[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 &lt;a&gt; 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')