diff options
Diffstat (limited to 'lib/main.js')
-rw-r--r-- | lib/main.js | 2500 |
1 files changed, 0 insertions, 2500 deletions
diff --git a/lib/main.js b/lib/main.js index 4917a5a..1a2dd7e 100644 --- a/lib/main.js +++ b/lib/main.js @@ -48,2506 +48,6 @@ var AddrArray = []; var topRow = {}; var bottomRow = {}; -/* - * - * xmlrpc.js beta version 1 Tool for creating XML-RPC formatted requests in - * JavaScript - * - * Copyright 2001 Scott Andrew LePera scott@scottandrew.com - * http://www.scottandrew.com/xml-rpc - * - * License: You are granted the right to use and/or redistribute this code only - * if this license and the copyright notice are included and you accept that no - * warranty of any kind is made or implied by the author. - * - */ - -function XMLRPCMessage(methodname) { - this.method = methodname || "system.listMethods"; - this.params = []; - return this; -} - -XMLRPCMessage.prototype.setMethod = function(methodName) { - if (!methodName) return; - this.method = methodName; -}; - -XMLRPCMessage.prototype.addParameter = function(data) { - if (arguments.length == 0) return; - this.params[this.params.length] = data; -}; - -XMLRPCMessage.prototype.xml = function() { - - let method = this.method; - - // assemble the XML message header - let xml = ""; - - xml += "<?xml version=\"1.0\"?>\n"; - xml += "<methodCall>\n"; - xml += "<methodName>" + method + "</methodName>\n"; - xml += "<params>\n"; - - // do individual parameters - for ( let i = 0; i < this.params.length; i++) { - let data = this.params[i]; - xml += "<param>\n"; - xml += "<value>" - + this.getParamXML(this.dataTypeOf(data), - data) + "</value>\n"; - xml += "</param>\n"; - } - - xml += "</params>\n"; - xml += "</methodCall>"; - - return xml; // for now -}; - -XMLRPCMessage.prototype.dataTypeOf = function(o) { - // identifies the data type - let type = typeof (o); - type = type.toLowerCase(); - switch (type) { - case "number": - if (Math.round(o) == o) - type = "i4"; - else - type = "double"; - break; - case "object": - let con = o.constructor; - if (con == Date) - type = "date"; - else if (con == Array) - type = "array"; - else - type = "struct"; - break; - } - return type; -}; - -XMLRPCMessage.prototype.doValueXML = function(type, data) { - let xml = "<" + type + ">" + data + "</" + type + ">"; - return xml; -}; - -XMLRPCMessage.prototype.doBooleanXML = function(data) { - let value = (data == true) ? 1 : 0; - let xml = "<boolean>" + value + "</boolean>"; - return xml; -}; - -XMLRPCMessage.prototype.doDateXML = function(data) { - let leadingZero = function (n) { - // pads a single number with a leading zero. Heh. - if (n.length == 1) - n = "0" + n; - return n; - }; - let dateToISO8601 = function(date) { - // wow I hate working with the Date object - let year = new String(date.getYear()); - let month = this.leadingZero(new String(date.getMonth())); - let day = this.leadingZero(new String(date.getDate())); - let time = this.leadingZero(new String(date.getHours())) + ":" - + this.leadingZero(new String(date.getMinutes())) + ":" - + this.leadingZero(new String(date.getSeconds())); - - let converted = year + month + day + "T" + time; - return converted; - }; - - let xml = "<dateTime.iso8601>"; - xml += dateToISO8601(data); - xml += "</dateTime.iso8601>"; - return xml; -}; - -XMLRPCMessage.prototype.doArrayXML = function(data) { - let xml = "<array><data>\n"; - for ( let i = 0; i < data.length; i++) { - xml += "<value>" - + this.getParamXML(this.dataTypeOf(data[i]), - data[i]) + "</value>\n"; - } - xml += "</data></array>\n"; - return xml; -}; - -XMLRPCMessage.prototype.doStructXML = function(data) { - let xml = "<struct>\n"; - for ( let i in data) { - xml += "<member>\n"; - xml += "<name>" + i + "</name>\n"; - xml += "<value>" - + this.getParamXML(this.dataTypeOf(data[i]), - data[i]) + "</value>\n"; - xml += "</member>\n"; - } - xml += "</struct>\n"; - return xml; -}; - -XMLRPCMessage.prototype.getParamXML = function(type, data) { - let xml; - switch (type) { - case "date": - xml = this.doDateXML(data); - break; - case "array": - xml = this.doArrayXML(data); - break; - case "struct": - xml = this.doStructXML(data); - break; - case "boolean": - xml = this.doBooleanXML(data); - break; - default: - xml = this.doValueXML(type, data); - break; - } - return xml; -}; - -// ============================================================== -let hlpr = function () { -}; - -/** - * Function for the management of the prototypal inheritace - * David Flanagan, Javascript: The Definitve Guide, - * IV. edition, O'Reilly, 2006, p. 168 - * - * @param superobject - * @return new object, it needs new prototype.constructor - * - * <pre> - * function Father(x) { - * this.family = x; - * } - * - * function Son(x,w) { - * Father.call(this,x); - * this.wife = w; - * } - * Son.prototype = hlpr.heir(Father); - * Son.prototype.constructor = Son; - * </pre> - */ -hlpr.heir = function(p) { - function f() {}; - f.prototype = p.prototype; - return new f(); -} - -/** - * 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. - */ -hlpr.isInList = function(mbr, list) { - if (!list) { - return false; - } - return (list.indexOf(mbr) !== -1); -}; - -/** - * format date to be in ISO format (just day part) - * - * @param date - * @return string with the formatted date - */ -hlpr.getISODate = function (dateStr) { - function pad(n) { - return n < 10 ? '0' + n : n; - } - let date = new Date(dateStr); - return date.getFullYear() + '-' + pad(date.getMonth() + 1) + '-' - + pad(date.getDate()); -}; - -/** - * Make sure value returned is Array - * - * @param Array/String - * @return Array - * - * If something else than Array or String is passed to the function - * the result will be untouched actual argument of the call. - */ -hlpr.valToArray = function valToArray(val) { - return (val instanceof Array) ? val : [val]; -}; - -/** - * Merges two comma separated string as a list and returns new string - * - * @param str String with old values - * @param value String/Array with other values - * @return String with merged lists - */ -hlpr.addCSVValue = function addCSVValue(str, value) { - let parts = (str.trim().length > 0 ? str.split(",") : []); - if (!hlpr.isInList(value,parts)) { - let newValue = hlpr.valToArray(value); - parts = parts.concat(newValue); - } - return parts.join(", "); -}; - -/** - * Treats comma separated string as a list and removes one item from it - * - * @param str String treated as a list - * @param value String with the value to be removed from str - * @return String with the resulting list comma separated - */ -hlpr.removeCSVValue = function removeCSVValue(str, value) { - str = str.trim(); - let parts = str ? str.split(",") : []; - let valueArr = value instanceof Array ? value : value.split(","); - parts = parts.filter(function(e,i,a) { - return (hlpr.isInList(e,valueArr)); - }); - return parts.join(","); -}; - -/** - * From given URL returns hostname of the server - * - * @param url String with the investigated URL - * @return String with hostname - */ -hlpr.getHost = function(url) { - let aElem = jetpack.tabs.focused.contentWindow.document.createElement("a"); - aElem.setAttribute("href",url); - return aElem.hostname; -} - -/** - * - */ -hlpr.getBugNo = function(url) { -// let bugNoTitle = this.doc.querySelector("#title > p").textContent.trim(); -// console.log("bugNoTitle = " + bugNoTitle); -// this.bugNo = this.getBugNo(this.doc.location.toString()); - let re = new RegExp(".*id=([0-9]+).*$"); - let bugNo = null; - let reResult = re.exec(url); - if (reResult[1]) { - bugNo = reResult[1]; - } - return bugNo; -}; - -/** - * Load text from URL - * - * @param URL String - * @param cb_function Function to be called when the download happens with - * the downloaded body of the HTTP message as the only parameter - * @param what optional Object argument representing this for this call - * @return none - */ -hlpr.loadText = function(URL, cb_function, what) { - if (what === undefined) { // missing optional argument - what = this; - } - - let req = new XMLHttpRequest(); - req.open("GET", URL, true); - req.onreadystatechange = function(aEvt) { - if (req.readyState == 4) { - if (req.status == 200) { - cb_function.call(what, req.responseText); - } else { - throw "Getting " + URL + "failed!"; - } - } - }; - req.send(""); -}; - -/** - * Load JSON from URL - * - * @param URL String - * @param cb_function Function to be called when the download happens with - * the downloaded JSON as the only parameter - * @param what optional Object argument representing this for this call - * @return none - */ -hlpr.loadJSON = function(URL, cb_function, what) { - if (what === undefined) { // missing optional argument - what = this; - } - - hlpr.loadText(URL, function(text) { - let data = JSON.parse(text); - cb_function.call(what, data); - }, what); -}; - -// ============================================================================ -// Color management methods -// originally from -// http://www.mjijackson.com/2008/02\ -// /rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript -function Color(r, g, b) { - this.Luminosity = 0.85; - this.Desaturated = 0.4; - - if (r instanceof Array) { - this.r = r[0]; - this.g = r[1]; - this.b = r[2]; - } else { - this.r = r; - this.g = g; - this.b = b; - } -} - -Color.prototype.update = function(r, g, b) { - this.r = r; - this.g = g; - this.b = b; -}; - -Color.prototype.hs = function(nStr) { - if (Number(nStr) === 0) { - return "00"; - } else if (nStr.length < 2) { - return "0" + nStr; - } else { - return nStr; - } -}; - -Color.prototype.toString = function() { - let rH = Number(this.r.toFixed()).toString(16); - let gH = Number(this.g.toFixed()).toString(16); - let bH = Number(this.b.toFixed()).toString(16); - return "#" + this.hs(rH) + this.hs(gH) + this.hs(bH); -}; - -/** - * Converts an RGB color value to HSL. Conversion formula adapted from - * http://en.wikipedia.org/wiki/HSL_color_space. Assumes r, g, and b are - * contained in the set [0, 255] and returns h, s, and l in the set [0, 1].4343 - * - * @param Number r The red color value - * @param Number g The green color value - * @param Number b The blue color value - * @return Array The HSL representation - */ -Color.prototype.hsl = function() { - let r = this.r / 255; - let g = this.g / 255; - let b = this.b / 255; - let max = Math.max(r, g, b), min = Math.min(r, g, b); - let h, s, l = (max + min) / 2; - - if (max === min) { - h = s = 0; // achromatic - } else { - let d = max - min; - s = l > 0.5 ? d / (2 - max - min) : d / (max + min); - switch (max) { - case r: - h = (g - b) / d + (g < b ? 6 : 0); - break; - case g: - h = (b - r) / d + 2; - break; - case b: - h = (r - g) / d + 4; - break; - } - h /= 6; - } - - return [ h, s, l ]; -}; - -/** - * Converts an HSL color value to RGB. Conversion formula adapted from - * http://en.wikipedia.org/wiki/HSL_color_space. Assumes h, s, and l are - * contained in the set [0, 1] and returns r, g, and b in the set [0, 255]. - * - * @param Number h The hue - * @param Number s The saturation - * @param Number l The lightness - * @return Array The RGB representation - */ -Color.prototype.hslToRgb = function(h, s, l) { - function hue2rgb(p, q, t) { - if (t < 0) { - t += 1; - } - if (t > 1) { - t -= 1; - } - if (t < 1 / 6) { - return p + (q - p) * 6 * t; - } - if (t < 1 / 2) { - return q; - } - if (t < 2 / 3) { - return p + (q - p) * (2 / 3 - t) * 6; - } - return p; - } - - let r, g, b; - - if (s === 0) { - r = g = b = l; // achromatic - } else { - let q = l < 0.5 ? l * (1 + s) : l + s - l * s; - let p = 2 * l - q; - r = hue2rgb(p, q, h + 1 / 3); - g = hue2rgb(p, q, h); - b = hue2rgb(p, q, h - 1 / 3); - } - - return [ r * 255, g * 255, b * 255 ]; -}; - -/** - * Converts an RGB color value to HSV. Conversion formula adapted from - * http://en.wikipedia.org/wiki/HSV_color_space. Assumes r, g, and b are - * contained in the set [0, 255] and returns h, s, and v in the set [0, 1]. - * - * @param Number r The red color value - * @param Number g The green color value - * @param Number b The blue color value - * @return Array The HSV representation - */ -Color.prototype.hsv = function() { - let r = this.r / 255; - let g = this.g / 255; - let b = this.b / 255; - let max = Math.max(r, g, b), min = Math.min(r, g, b); - let h, s, v = max; - - let d = max - min; - s = max === 0 ? 0 : d / max; - - if (max === min) { - h = 0; // achromatic - } else { - switch (max) { - case r: - h = (g - b) / d + (g < b ? 6 : 0); - break; - case g: - h = (b - r) / d + 2; - break; - case b: - h = (r - g) / d + 4; - break; - } - h /= 6; - } - - return [ h, s, v ]; -}; - -/** - * Converts an HSV color value to RGB. Conversion formula adapted from - * http://en.wikipedia.org/wiki/HSV_color_space. Assumes h, s, and v are - * contained in the set [0, 1] and returns r, g, and b in the set [0, 255]. - * - * @param Number h The hue - * @param Number s The saturation - * @param Number v The value - * @return Array The RGB representation - */ -Color.prototype.hsvToRgb = function(h, s, v) { - let r, g, b; - - let i = Math.floor(h * 6); - let f = h * 6 - i; - let p = v * (1 - s); - let q = v * (1 - f * s); - let t = v * (1 - (1 - f) * s); - - switch (i % 6) { - case 0: - r = v; - g = t; - b = p; - break; - case 1: - r = q; - g = v; - b = p; - break; - case 2: - r = p; - g = v; - b = t; - break; - case 3: - r = p; - g = q; - b = v; - break; - case 4: - r = t; - g = p; - b = v; - break; - case 5: - r = v; - g = p; - b = q; - break; - } - - return [ r * 255, g * 255, b * 255 ]; -}; - -/** - * Provide - */ -Color.prototype.lightColor = function() { - let hslArray = this.hsl(); - let h = Number(hslArray[0]); - let s = Number(hslArray[1]) * this.Desaturated; - let l = this.Luminosity; - let desA = this.hslToRgb(h, s, l); - return new Color(desA[0], desA[1], desA[2]); -}; - -// ==================================================================================== -// Logger - -function Logger(store, abbsMap) { - this.EmptyLogsColor = new Color(0, 255, 0); - this.FullLogsColor = new Color(0, 40, 103); - - this.store = store; - this.abbsMap = abbsMap; -}; - -Logger.prototype.addLogRecord = function(that) { - let rec = {}; - rec.date = new Date(); - rec.url = that.doc.location.toString(); - rec.title = that.title; - let comment = jetpack.tabs.focused.contentWindow.prompt( - "Enter comments for this comment"); - if (comment && comment.length > 0) { - comment = comment.trim(); - rec.comment = comment; - let recKey = hlpr.getISODate(rec.date) + "+" + hlpr.getHost(rec.url) - + "+" + that.bugNo; - let clearLogAElem = that.doc.getElementById("clearLogs"); - clearLogAElem.style.color = this.FullLogsColor; - clearLogAElem.style.fontWeight = "bolder"; - if (this.store[recKey]) { - this.store[recKey].comment += "<br/>\n" + comment; - } else { - this.store[recKey] = rec; - } - jetpack.storage.simple.sync(); - return rec; - } else { - return comment; - } -}; - -Logger.prototype.getBugzillaAbbr = function(url) { - // for https://bugzilla.redhat.com/show_bug.cgi?id=579123 get RH - // for https://bugzilla.mozilla.org/show_bug.cgi?id=579123 get MoFo - var abbr = this.abbsMap[hlpr.getHost(url)]; - return abbr; -} - -Logger.prototype.timeSheetRecordsPrinter = function(body, records) { - let that = this; - let commentBugRE = new RegExp("[bB]ug\\s+([0-9]+)","g"); - // sort the records into temporary array - let tmpArr = []; - - for ( let i in records) { - if (records.hasOwnProperty(i)) { - tmpArr.push( [ i, records[i] ]); - } - } - tmpArr.sort(function(a, b) { - return a[0] > b[0] ? 1 : -1; - }); - - let currentDay = ""; - // now print the array - tmpArr.forEach(function(rec) { - let x = rec[1]; - let dayStr = hlpr.getISODate(x.date); - let host = hlpr.getHost(x.url); - let BZName = that.getBugzillaAbbr(x.url); - let bugNo = hlpr.getBugNo(x.url); - if (dayStr != currentDay) { - currentDay = dayStr; - body.innerHTML += "<hr/><p><strong>" + currentDay - + "</strong></p>"; - } - // replace "bug ####" with a hyperlink to the current bugzilla - let comment = x.comment.replace(commentBugRE, - "<a href='http://"+host+"/show_bug.cgi?id=$1'>$&</a>"); - body.innerHTML += "<p><em><a href='" - + x.url - + "'>Bug " - + BZName + "/" + bugNo + ": " - + x.title - + "</a>" - + " </em>\n<br/>" + comment + "</p>"; - }); -}; - -/** - * - */ -Logger.prototype.createBlankPage = function (ttl, bodyBuildCB) { - let title = ttl || "Yet another untitled page"; - let that = this; - - let logTab = jetpack.tabs.open("about:blank"); - jetpack.tabs.onReady(function() { - let otherDoc = logTab.contentDocument; - otherDoc.title = title; - otherDoc.body.innerHTML = "<h1>" + title + "</h1>"; - bodyBuildCB.call(that, otherDoc.body); - logTab.focus(); - }); -}; - -Logger.prototype.generateTimeSheet = function(body) { - let doc = body.ownerDocument; - this.timeSheetRecordsPrinter(body, this.store); -}; - -// ==================================================================================== -// BZPage's methods - -function BZPage(doc) { - // constants - this.SalmonPink = new Color(255, 224, 176); // RGB 255, 224, 176; HSL 36, 2, - // 85 - this.ReporterColor = new Color(255, 255, 166); // RGB 255, 255, 166; HSL 60, 2, - // 83 - this.RE = { - Comment: new RegExp("^\\s*#"), // unsused - BlankLine: new RegExp("^\\s*$"), // unused - // nová řádka - // [ 65.631] (--) intel(0): Chipset: "845G" - Chipset: new RegExp("^\\s*\\[?[ 0-9.]*\\]?\\s*\\(--\\) "+ - "([A-Za-z]+)\\([0-9]?\\): Chipset: (.*)$"), - ATIgetID: new RegExp("^.*\\(ChipID = 0x([0-9a-fA-F]+)\\).*$"), - Abrt: new RegExp("^\\s*\\[abrt\\]"), - signalHandler: new RegExp("^\\s*#[0-9]*\\s*<signal handler called>"), - frameNo: new RegExp("^\\s*#([0-9]*)\\s") - }; - - - // initialize dynamic properties - this.doc = doc; - this.packages = this.getInstalledPackages(); - if ("commentStrings" in config.gJSONData) { - this.commentStrings = config.gJSONData.commentStrings; - } - - if ("constantData" in config.gJSONData) { - this.constantData = config.gJSONData.constantData; - } - - if ("CCmaintainer" in config.gJSONData.constantData) { - this.defBugzillaMaintainerArr = config.gJSONData.constantData.CCmaintainer; - } - - if ("submitsLogging" in config.gJSONData.configData && - config.gJSONData.configData.submitsLogging) { - this.log = config.logger; - this.setUpLogging(); - } - - this.submitHandlerInstalled = false; - this.bugNo = hlpr.getBugNo(this.doc.location.toString()); - this.reporter = this.getReporter(); - this.product = this.getOptionValue("product"); - this.component = this.getOptionValue("component"); - this.version = this.getVersion(); - this.title = this.doc.getElementById("short_desc_nonedit_display").textContent; - this.CCList = this.getCCList(); - - this.generateButtons(); -} - -/** - * - */ -BZPage.prototype.getInstalledPackages = function() { - let installedPackages = {}; - if (config.gJSONData && ("commentPackages" in config.gJSONData)) { - let enabledPackages = jetpack.storage.settings.enabledPacks.split(/[, ]/); - for each (let pkg in enabledPackages) { - if (pkg in config.gJSONData.commentPackages) { - installedPackages[pkg] = config.gJSONData.commentPackages[pkg]; - } - } - } - return installedPackages; -}; - -/** - * Actual execution function - * - * @param cmdLabel String with the name of the command to be executed - * @param cmdParams Object with the appropriate parameters for the command - */ -BZPage.prototype.centralCommandDispatch = function (cmdLabel, cmdParams) { - switch (cmdLabel) { - case "resolution": - case "product": - case "component": - case "version": - case "priority": - this.selectOption(cmdLabel, cmdParams); - break; - case "status": - this.selectOption("bug_status", cmdParams); - break; - case "platform": - this.selectOption("rep_platform", cmdParams); - break; - case "os": - this.selectOption("op_sys", cmdParams); - break; - case "severity": - this.selectOption("bug_severity", cmdParams); - break; - case "target": - this.selectOption("target_milestone", cmdParams); - break; - case "addKeyword": - this.addStuffToTextBox("keywords",cmdParams); - break; - case "removeKeyword": - this.removeStuffFromTextBox("keywords", cmdParams); - break; - case "addWhiteboard": - this.addStuffToTextBox("status_whiteboard",cmdParams); - break; - case "removeWhiteboard": - this.removeStuffFromTextBox("status_whiteboard",cmdParams); - break; - case "assignee": - this.changeAssignee(cmdParams); - break; - case "qacontact": - this.clickMouse("bz_qa_contact_edit_action"); - this.doc.getElementById("qa_contact").value = cmdParams; - break; - case "url": - this.clickMouse("bz_url_edit_action"); - this.doc.getElementById("bug_file_loc").value = cmdParams; - break; - // TODO dependson/blocked doesn't work. Find out why. - case "addDependsOn": - this.clickMouse("dependson_edit_action"); - this.addStuffToTextBox("dependson", cmdParams); - break; - case "removeDependsOn": - this.clickMouse("dependson_edit_action"); - this.removeStuffFromTextBox("dependson", cmdParams); - break; - case "addBlocks": - this.clickMouse("blocked_edit_action"); - this.addStuffToTextBox("blocked", cmdParams); - break; - case "removeBlocks": - this.clickMouse("blocked_edit_action"); - this.removeStuffFromTextBox("blocked", cmdParams) - break; - case "comment": - this.addStuffToTextBox("comment", cmdParams); - break; - case "commentIdx": - let commentText = this.commentStrings[cmdParams]; - this.addStuffToTextBox("comment", commentText); - break; - case "setNeedinfo": - // cmdParams are actually ignored for now; we may in future - // distinguish different actors to be target of needinfo - this.setNeedinfoReporter(); - break; - case "addCC": - this.addToCCList(cmdParams); - break; - // TODO flags, see also - - case "commit": - if (cmdParams) { - // Directly commit the form - this.doc.forms.namedItem("changeform").submit(); - } - break; - } -}; - -/** - * Take the ID of the package/id combination, and execute it - * - * @param String combined package + "//" + id combination - * Fetches the command object from this.installedPackages and then - * goes through all commands contained in it, and calls - * this.centralCommandDispatch to execute them. - */ -BZPage.prototype.executeCommand = function(cmd) { - let [pkg, id] = cmd.split("//"); - let commentObj = this.packages[pkg][id]; - - for (let key in commentObj) { - this.centralCommandDispatch(key,commentObj[key]); - } -}; - -/** - * Add XGL to the CC list - * - * @param evt Event which made this function active - * @return none - */ -BZPage.prototype.changeAssignee = function(newAssignee) { - let defAssigneeButton = null; - this.addToCCList(this.owner); - if (newAssignee === null) { - this.doc.getElementById("set_default_assignee").removeAttribute( - "checked"); - return ; - } - - if (this.getDefaultAssignee) { - if (newAssignee == "default") { - let defAss = this.getDefaultAssignee(); - if (defAss) { - newAssignee = defAss; - } else { - return ; - } - } - } - - if (newAssignee) { - this.clickMouse("bz_assignee_edit_action"); - this.doc.getElementById("assigned_to").value = newAssignee; - this.doc.getElementById("set_default_assignee").checked = false; - if (defAssigneeButton = this.doc - .getElementById("setDefaultAssignee_btn")) { - defAssigneeButton.style.display = "none"; - } - } -}; - -/** - * Adds new option to the 'comment_action' scroll down box - * - * @param pkg String package name - * @param cmd String with the name of the command - * If the 'comment_action' scroll down box doesn't exist, this - * function will set up new one. - */ -BZPage.prototype.addToCommentsDropdown = function(pkg, cmd) { - let select = this.doc.getElementById("comment_action"); - if (!select) { - let that = this; - this.doc.getElementById("comments").innerHTML += - "<div id='make_bugzilla_comment_action'>" + - " <label for='comment_action'>Add Comment: </label>" + - " <select id='comment_action'>" + - " <option value=''>-- Select Comment from List --</option>" + - "</div>"; - select = this.doc.getElementById("comment_action"); - select.addEventListener("change", function () { - let valueElement = that.doc.getElementById("comment_action"); - if (valueElement) { - let value = valueElement.getAttribute("value"); - } else { - return; - } - that.executeCommand(value); - }, false); - } - - let opt = that.doc.createElement("option"); - opt.value = pkg + "//" + cmd; - opt.textContent = this.packages[pkg][cmd].name; - select.appendChild(opt); -}; - -/** - * 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 location Object around which the new button will be added - * @param after Boolean before or after location ? - * @param pkg String which package to take the command from - * @param id String which command to take - * @return none - */ -BZPage.prototype.createNewButton = function(location, after, pkg, id) { - let that = this; - let cmdObj = this.packages[pkg][id]; - let newId = id + "_btn"; - let label = cmdObj["name"]; - - // protection against double-firings - if (this.doc.getElementById(newId)) { - console.error("Element with id " + newId + "already exists!"); - return ; - } - - // creation of button might be conditional on existence of data in constantData - if ("ifExist" in cmdObj) { - if (!(cmdObj["ifExist"] in this.constantData)) { - return ; - } - } - - let newButton = this.doc.createElement("input"); - newButton.setAttribute("id", newId); - newButton.setAttribute("type", "button"); - newButton.value = label; - newButton.addEventListener("click", function(evt) { - that.executeCommand(pkg + "//" + id); - }, false); - - let originalLocation = this.doc.getElementById(location); - - if (after) { - originalLocation.parentNode.insertBefore(newButton, - originalLocation.nextSibling); - originalLocation.parentNode.insertBefore(this.doc - .createTextNode("\u00A0"), newButton); - } else { - originalLocation.parentNode.insertBefore(newButton, originalLocation); - originalLocation.parentNode.insertBefore(this.doc - .createTextNode("\u00A0"), originalLocation); - } -}; - -/** - * - */ -BZPage.prototype.generateButtons = function() { - let topRowPosition = "topRowPositionID"; - let bottomRowPosition = "commit"; - - // create anchor for the top toolbar - let commentBox = this.doc.getElementById("comment"); - let brElement = this.doc.createElement("br"); - brElement.setAttribute("id",topRowPosition); - commentBox.parentNode.normalize(); - commentBox.parentNode.insertBefore(brElement, commentBox); - - for (let pkg in this.packages) { - for (let cmdIdx in this.packages[pkg]) { - let cmdObj = this.packages[pkg][cmdIdx]; - switch (cmdObj.position) { - case "topRow": - this.createNewButton(topRowPosition, false, pkg, cmdIdx); - break; - case "bottomRow": - this.createNewButton(bottomRowPosition, false, pkg, cmdIdx); - break; - case "dropDown": - this.addToCommentsDropdown(pkg,cmdIdx); - break; - default: // [+-]ID - let firstChr = cmdObj.position.charAt(0); - let newId = cmdObj.position.substr(1); - this.createNewButton(newId, firstChr == "+", pkg, cmdIdx); - break; - } - } - } -}; - -/** - * Get the current email of the reporter of the bug. - * - * @return string - */ -BZPage.prototype.getReporter = function() { - return this.doc - .querySelector("#bz_show_bug_column_2 > table .vcard:first-of-type > a").textContent; -}; - -/** - * Get the current version of the Fedora release ... even if changed meanwhile - * by bug triager. - * - * @return string (integer for released Fedora, float for RHEL, rawhide) - */ -BZPage.prototype.getVersion = function() { - let verStr = this.getOptionValue("version").toLowerCase(); - let verNo = 0; - if (/rawhide/.test(verStr)) { - verNo = 999; - } else { - verNo = Number(verStr); - } - return verNo; -}; - -BZPage.prototype.commentsWalker = function(fce) { - let comments = this.doc.getElementById("comments").getElementsByClassName( - "bz_comment"); - Array.forEach(comments, function(item) { - fce(item); - }, this); -}; - -/** - * Set background color of all comments made by reporter in ReporterColor color - * - */ -BZPage.prototype.checkComments = function() { - let that = this; - this.commentsWalker(function(x) { - let email = x.getElementsByClassName("vcard")[0] - .getElementsByTagName("a")[0].textContent; - if (new RegExp(that.reporter).test(email)) { - x.style.backgroundColor = that.ReporterColor.toString(); - } - }); -}; - -BZPage.prototype.collectComments = function() { - let outStr = ""; - this.commentsWalker(function(x) { - outStr += x.getElementsByTagName("pre")[0].textContent + "\n"; - }); - return outStr.trim(); -}; - - -/** - * 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 - * - * FIXME bugzilla-comments version has this signature: - * selectOption = function selectOption(select, value) { - let doc = select[0].ownerDocument; - select.val(value); - */ -BZPage.prototype.selectOption = function(id, label) { - let sel = this.doc.getElementById(id); - sel.value = label; - let intEvent = this.doc.createEvent("HTMLEvents"); - intEvent.initEvent("change", true, true); - sel.dispatchEvent(intEvent); -}; - -/** - * Send mouse click to the specified element - * - * @param String ID of the element to send mouseclick to - * @return None - */ -BZPage.prototype.clickMouse = function(targetID) { - let localEvent = this.doc.createEvent("MouseEvents"); - localEvent.initMouseEvent("click", true, true, this.doc.defaultView, 0, 0, - 0, 0, 0, false, false, false, false, 0, null); - this.doc.getElementById(targetID).dispatchEvent(localEvent); -}; - -/** - * 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 Object chosen element - */ -BZPage.prototype.filterByRegexp = function(list, chosingMark) { - let chosenPair = []; - if (list.length > 0) { - chosenPair = list.filter(function(pair) { - return new RegExp(pair.regexp, "i").test(chosingMark); - }); - } - if (chosenPair.length > 0) { - return chosenPair[0].addr; - } else { - return ""; - } -}; - -/** - * Add object to the text box (comment box or status whiteboard) - * - * @param id String with the id of the element - * @param stuff String/Array to be added to the comment box - * - * @return none - */ -BZPage.prototype.addStuffToTextBox = function(id, stuff) { - let textBox = this.doc.getElementById(id); - if (textBox.tagName.toLowerCase() === "textarea") { - stuff = textBox.value ? "\n\n" + stuff : stuff; - textBox.value += stuff; - } else { - textBox.value = hlpr.addCSVValue(textBox.value,stuff); - } -}; - -/** - * Remove a keyword from the element if it is there - * - * @param id String with the id of the element - * @param stuff String/Array with keyword(s) to be removed - */ -BZPage.prototype.removeStuffFromTextBox = function(id, stuff) { - let changedElement = this.getElementById(id); - changedElement.value = hlpr.removeCSVValue(changedElement.value,stuff); -} - -/** - * generalized hasKeyword ... search in the value of the box with given id - * - * @param id String with ID of the element we want to check - * @param str String to be searched for - * @return Boolean found? - */ -BZPage.prototype.idContainsWord = function(id, str) { - try { - var kwd = this.doc.getElementById(id).value; - } catch (e) { - // For those who don't have particular element at all or if it is empty - return false; - } - return (kwd.trim().indexOf(str) != -1); -}; - -/** - * Check for the presence of a keyword - * - * @param str String with the keyword - * @return Boolean - */ -BZPage.prototype.hasKeyword = function(str) { - return (this.idContainsWord('keywords', str)); -}; - -/** - * - */ -BZPage.prototype.getOptionValue = function(id) { - // Some special bugs don't have version for example - let element = this.doc.getElementById(id); - if (element) { - return element.value; - } else { - console.log("Failed to find element with id = " + id); - return "#NA"; - } -}; - -/** - * Set the bug to NEEDINFO state - * - * Working function. - * @return none - * @todo TODO we may extend this to general setNeedinfo function - * with parameter [reporter|assignee|general-email-address] - */ -BZPage.prototype.setNeedinfoReporter = function() { - this.clickMouse("needinfo"); - this.selectOption("needinfo_role", "reporter"); -}; - -/** - * - */ -BZPage.prototype.getOwner = function() { - let priorityParent = this.doc.querySelector("label[for~='target_milestone']") - .parentNode.parentNode.parentNode; - let assigneeAElement = priorityParent.querySelector("tr:nth-of-type(1) a.email"); - let assgineeHref = decodeURI(assigneeAElement.getAttribute("href")); - let email = assgineeHref.split(":")[1]; - return email; -}; - -/** - * Get login of the currently logged-in user. - * - * @return String with the login name of the currently logged-in user - */ -BZPage.prototype.getLogin = function () { - let lastLIElement = this.doc.querySelector("#header ul.links li:last-of-type"); - let loginArr = lastLIElement.textContent.split("\n"); - let loginStr = loginArr[loginArr.length - 1].trim(); - return loginStr; -}; - -/** - * Return maintainer which is per default by bugzilla - * (which is not necessarily the one who is default maintainer per component) - * - * @return String with the maintainer's email address - */ -BZPage.prototype.getDefaultBugzillaMaintainer = function(component) { - let address = this.filterByRegexp(this.defBugzillaMaintainerArr, component); - return address; -} - -/** - * collect the list of attachments in a structured format - * - * @return Array of arrays, one for each attachments; - * each record has string name of the attachment, integer its id number, - * string of MIME type, integer of size in kilobytes, and the whole - * element itself - */ -BZPage.prototype.getAttachments = function() { - let outAtts = []; - let atts = this.doc.getElementById("attachment_table") - .getElementsByTagName("tr"); - for ( let i = 1, ii = atts.length - 1; i < ii; i++) { - outAtts.push(this.parseAttachmentLine(atts[i])); - } - return outAtts; -}; - -/** - * returns password from the current storage, or if there isn't - * one, then it will ask user for it. - * - * @return String with the password - */ -BZPage.prototype.getPassword = function() { - if (jetpack.storage.settings.BZpassword) { - return jetpack.storage.settings.BZpassword; - } else { - let prompts = Components.classes["@mozilla.org/embedcomp/prompt-service;1"] - .getService(Components.interfaces.nsIPromptService); - let password = { - value : "" - }; // default the password to pass - let check = { - value : true - }; // default the checkbox to true - let result = prompts.promptPassword(null, "Title", "Enter password:", - password, null, check); - // result is true if OK was pressed, false if cancel was pressed. - // password.value is - // set if OK was pressed. The checkbox is not displayed. - if (result) { - let passwordText = password.value; - jetpack.storage.settings.BZpassword = passwordText; - jetpack.storage.simple.sync(); - return passwordText; - } - } - return null; -}; - -/** - * - */ -BZPage.prototype.setUpLogging = function() { - // For adding additional buttons to the top toolbar - let additionalButtons = this.doc.querySelector("#bugzilla-body *.related_actions"); - let that = this; - - // logging all submits for timesheet - // FIXME we should merge in functionality of RHBugzillaPage.submitCallback - // and actually make it working - // Maybe rewriting whole offline capability into a separate object? - if (!this.submitHandlerInstalled) { - console.log("Installing submit callback!"); - this.doc.forms.namedItem("changeform").addEventListener("submit",function (evt) { - console.log("Submit callback!"); - let resp = that.log.addLogRecord(that); - console.log("resp = " + resp); - if (resp === null) { - console.log("Avoiding submitting!"); - // FIXME doesn't work ... still submitting' - evt.stopPropagation(); - evt.preventDefault(); - } - }, false); - this.submitHandlerInstalled = true; - } - - let generateTimeSheetUI = this.doc.createElement("li"); - generateTimeSheetUI.innerHTML = "\u00A0-\u00A0<a href='#' id='generateTSButton'>" - + "Generate timesheet</a>"; - additionalButtons.appendChild(generateTimeSheetUI); - this.doc.getElementById("generateTSButton").addEventListener( - "click", - function(evt) { - that.log.createBlankPage.call(that.log, "TimeSheet", - that.log.generateTimeSheet); - evt.stopPropagation(); - evt.preventDefault(); - }, false); - - let clearLogsUI = this.doc.createElement("li"); - clearLogsUI.innerHTML = "\u00A0-\u00A0<a href='#' id='clearLogs'>" - + "Clear logs</a>"; - additionalButtons.appendChild(clearLogsUI); - let clearLogAElem = this.doc.getElementById("clearLogs"); - clearLogAElem.addEventListener("click", function() { - that.log.store = {}; - jetpack.storage.simple.sync(); - this.style.color = that.log.EmptyLogsColor; - this.style.fontWeight = "normal"; - console.log("this.store wiped out!"); - }, false); - - if (!this.store) { - console.log("No this.store defined!"); - this.store = {}; - } - - if (this.log.store.length > 0) { - clearLogAElem.style.color = this.log.FullLogsColor; - clearLogAElem.style.fontWeight = "bolder"; - } else { - clearLogAElem.style.color = this.log.EmptyLogsColor; - clearLogAElem.style.fontWeight = "normal"; - } -}; - -/** - * adds a person to the CC list, if it isn't already there - * - * @param who String with email address or "self" if the current user - * of the bugzilla should be added - */ -BZPage.prototype.addToCCList = function(who) { - if (!who) { - return ; - } - if (who == "self") { - this.doc.getElementById("addselfcc").checked = true; - } else { - this.clickMouse("cc_edit_area_showhide"); - if (!hlpr.isInList(who, this.CCList)) { - this.addStuffToTextBox("newcc",who); - } - } -}; - -/** - * a collect a list of emails on CC list - * - * @return Array with email addresses as Strings. - */ -BZPage.prototype.getCCList = function() { - let CCListSelect = this.doc.getElementById("cc"); - outCCList = []; - if (CCListSelect) { - outCCList = Array.map(CCListSelect.options, function(item) { - return item.value; - }); - } - return outCCList; -}; - -// ==================================================================================== -// MozillaBugzilla object - -MozillaBugzilla = function (doc) { - BZPage.call(this, doc) -}; - -MozillaBugzilla.prototype = hlpr.heir(BZPage); -MozillaBugzilla.prototype.constructor = MozillaBugzilla; - -// ==================================================================================== -// RHBugzillaPage object - -RHBugzillaPage = function(doc) { - // For identification of graphics card - const manuChipStrs = [ [ "ATI Radeon", "ATI", "1002" ], - [ "ATI Mobility Radeon", "ATI", "1002" ], - [ "Intel Corporation", "INTEL", "8086" ], [ "NVIDIA", "NV", "10de" ] ]; - - // http://en.wikipedia.org/wiki/HSL_color_space - // when only the value of S is changed - // stupido!!! the string is value in hex for each color - this.RHColor = new Color(158, 41, 43); // RGB 158, 41, 43; HSL 359, 1, 39 - this.FedoraColor = new Color(0, 40, 103); // RGB 0, 40, 103; HSL 359, 1, 39 - this.RawhideColor = new Color(0, 119, 0); // or "green", or RGB 0, 119, 0, or - // HSL - // 120, 0, 23 - this.RHITColor = new Color(102, 0, 102); // RGB 102, 0, 102; HSL 300, 0, 20 - // END OF CONSTANTS - - // Prepare for query buttons - // FIXME getting null for commentArea sometimes - let commentArea = doc.getElementById("comment_status_commit"); - if (commentArea) { - let brElementPlacer = commentArea.getElementsByTagName("br")[0]; - brElementPlacer.setAttribute("id","brElementPlacer_location"); - brElementPlacer.parentNode.insertBefore(doc.createElement("br"), - brElementPlacer); - } - - // inheritance ... call superobject's constructor - BZPage.call(this,doc); - - let that = this; - this.reqCounter = 0; - this.signaturesCounter = 0; - this.chipMagicInterestingLine = ""; - - this.login = this.getLogin(); - this.password = this.getPassword(); - - let ITbutton = this.doc.getElementById("cf_issuetracker"); - this.its = ITbutton ? ITbutton.value.trim() : ""; - - // set default assignee on change of the component - this.doc.getElementById("component").addEventListener("change", - function() { - that.component = that.getOptionValue("component"); - that.changeAssignee("default"); - }, false); - - // getBadAttachments - this.XorgLogAttList = []; - this.XorgLogAttListIndex = 0; - this.attachments = this.getAttachments(); - this.markBadAttachments(); - this.setDefaultAssignee(); - - // Dig out backtrace - this.btSnippet = ""; - - let parseAbrtBacktraces = config.gJSONData.configData.parseAbrtBacktraces; - if (parseAbrtBacktraces && this.RE.Abrt.test(this.title)) { - this.pasteBacktraceInComments(); - } - - // Take care of signature for Fedora bugzappers - if (config.gJSONData.configData.signature.length > 0) { - let signatureFedoraString = config.gJSONData.configData.signature; - this.doc.forms.namedItem("changeform").addEventListener("submit", - function() { - if (this.signaturesCounter < 1) { - that.addStuffToTextBox("comment", signatureFedoraString); - this.signaturesCounter += 1; - } - }, false); - } - - this.setBranding(); - this.checkComments(); - - // TODO Get compiz bugs as well - if ((config.gJSONData.configData.PCIIDsURL - && (config.PCI_ID_Array.length > 0)) - && this.maintCCAddr === "xgl-maint@redhat.com") { - // Add find chip magic button - let whiteboard_string = this.doc.getElementById("status_whiteboard").value; - if (!/card_/.test(whiteboard_string)) { - this.fillInChipMagic(); - } - } -} // END OF RHBugzillaPage CONSTRUCTOR - -RHBugzillaPage.prototype = hlpr.heir(BZPage); -RHBugzillaPage.prototype.constructor = RHBugzillaPage; - -/** - * Find default assignee based on the current component - * - * @return String what would be a default assignee if - * we haven't set it up. - */ -RHBugzillaPage.prototype.getDefaultAssignee = function() { - return this.filterByRegexp(this.constantData.defaultAssignee, - this.component).toLowerCase(); -} - -/** - * Set default assignee - * - * @return none - * sets this.defaultAssignee property according to defaultAssignee list - */ -RHBugzillaPage.prototype.setDefaultAssignee = function() { - this.defaultAssignee = this.getDefaultAssignee(); - let defAss = this.defaultAssignee; - - // Add setting default assignee - if ((defAss.length > 0) && (defAss !== this.getOwner())) { - this.constantData.defaultAssigneeTrigger = true; - this.createNewButton("bz_assignee_edit_container",true,"rh-common","setDefaultAssignee"); - } -}; - -/** - * Auxiliary function to computer more complicated resolution - */ -RHBugzillaPage.prototype.closeSomeRelease = function() { - // for RAWHIDE close as RAWHIDE, - // if active selection -> CURRENTRELEASE - // and put the release version to - // "Fixed in Version" textbox - // otherwise -> NEXTRELEASE - let verNo = this.getVersion(); - this.selectOption("bug_status", "CLOSED"); - let text = ""; - let resolution = ""; - - if (jetpack.selection.text) { - text = jetpack.select.text.trim(); - } - if (text.length > 0) { - resolution = "CURRENTRELEASE"; - this.doc.getElementById("cf_fixed_in").value = text; - } else if (verNo === 999) { - resolution = "RAWHIDE"; - } else { - resolution = "NEXTRELEASE"; - } - this.centralCommandDispatch("resolution", resolution); -}; - -/** - * Additional commands specific for this subclass, overriding superclass one. - */ -RHBugzillaPage.prototype.centralCommandDispatch = function(cmdLabel, cmdParams) { - switch (cmdLabel) { - // Set up our own commands - case "closeUpstream": - this.addClosingUpstream(); - break; - case "computeResolution": - this.closeSomeRelease(); - break; - case "queryStringOurBugzilla": - this.queryForSelection(); - break; - case "queryUpstreamBugzilla": - this.queryUpstream(); - break; - case "sendBugUpstream": - this.sendBugUpstream(); - break; - case "markTriaged": - this.markBugTriaged(); - break; - case "chipMagic": - let splitArr = cmdParams.split("\t"); - this.fillInWhiteBoard(splitArr[0], splitArr[1]); - break; - // If we don't have it here, call superclass method - default: - BZPage.prototype.centralCommandDispatch.call(this, cmdLabel, cmdParams); - break; - } -}; - - -/* Offline supporting functions */ -/** - * - * @todo FIXME this probably makes a closure and a memory leak name='changeform' - * investigate - * https://developer.mozilla.org/en/How_to_Turn_Off_Form_Autocompletion - * - * <form method="post" action="process_bug.cgi" autocomplete="off"> - * - * Reading - * http://www.w3.org/TR/1999/REC-html401-19991224/interact/forms.html#h-17.13 - * random notes: - 17.13.3 provides all steps necessary - enctype != - * application/x-www-form-urlencoded => SHOULD fails (no further questions - * needed) - http://www.w3.org/MarkUp/html-spec/html-spec_8.html#SEC8.2.1. is - * nice explanation (albeit quite dated) - on multiple values - * http://www.w3.org/TR/1999/REC-html401-19991224/interact/forms.html#h-17.6.1 - - * příliš jednoduché - * http://www.innovation.ch/java/HTTPClient/emulating_forms.html - - */ -RHBugzillaPage.prototype.serializeForm = function(form) { - let serialForm = { - dataOut : "", - name : form.name, - method : form.method, - acceptCharset : form.acceptCharset, - action : form.action, // TODO shouldn't we get a non-relative URL? - enctype : form.enctype, - cookie : this.doc.cookie, - autocomplete : form.getAttribute("autocomplete"), - bugNo : this.bugNo - }; - - function genURIElement(sName, sValue) { - return encodeURIComponent(sName) + "=" + encodeURIComponent(sValue); - } - - /** - * @param o - * control to be serialized - * @return String with the serialized control - */ - function serializeControl(element) { - let val = element.value; - // console.log("val.toSource() = " + val.toSource()); - /* - * on HTMLSelectElement we have an attribute 'type' of type DOMString, - * readonly The type of this form control. This is the string - * "select-multiple" when the multiple attribute is true and the string - * "select-one" when false. - */ - if ((val == null) || (val == undefined) || (val == "")) { - return; - } else if (val instanceof Array) { - return val.map(function(x) { - return genURIElement(element.name, x.value); - }).join("&"); - } else if (val instanceof String) { - return genURIElement(element.name, val); - } else { // assume HTMLCollection - return Array.map(val, function(x) { - return genURIElement(element.name, x.value); - }).join("&"); - } - } - - serialForm.dataOut = Array.filter(form.elements,function(el) { - return !el.disabled && el.name && - // FIXME shouldn't I just add && el.value here? - (el.checked || /select|textarea/i.test(el.nodeName) || - /text|hidden|password|search/i.test(el.type)); - }).map(serializeControl).join("&"); - return serialForm; -}; - -//RHBugzillaPage.prototype.submitCallback = function(evt) { -// console.log("Submit Callback!"); -// if (jetpack.__parent__.navigator.onLine) { -// let serForm = this -// .serializeForm(jetpack.tabs.focused.contentWindow.document.forms -// .namedItem("changeform")); -//// console.log("serForm:\n" + serForm.toSource()); -// } else { -// let serForm = this -// .serializeForm(jetpack.tabs.focused.contentWindow.document.forms -// .namedItem("changeform")); -// myStorage.forms[this.bugNo] = serForm; -// evt.stopPropagation(); -// evt.preventDefault(); -// } -//}; - -/** - * - * - * Yes, this is correct, this is NOT method of RHBugzillaPage! - */ -/*function onlineCallback() { - function deserializeAndSend(formData) { - // FIXME notImplemented - // is it enough to just - // run XMLHttpRequest? Probably yes, this is just a form - // and this is just a HTTP request - // it is probably better to get already processed - // application/x-www-form-urlencoded - // see http://htmlhelp.com/reference/html40/forms/form.html for details - // and also https://developer.mozilla.org/en/AJAX/Getting_Started - // what's? - // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference\ - // /Global_Functions/encodeURI & co. - // this seems to be also interesting - // https://developer.mozilla.org/en/Code_snippets/Post_data_to_window - console.error("Sending bugs not implemented yet!"); - return ""; // FIXME check other HTTP headers to be set - - let bugID = formData.bugNo; - let req = new XMLHttpRequest(); - req.open("POST", formData.action, true); - // FIXME co očekávám za odpověď? req.overrideMimeType("text/xml"); - // * Accept-Encoding - // * Accept-Language - // * Accept (MIME types) - req.setRequestHeader("Connection", "keep-alive"); - req.setRequestHeader("Keep-Alive", 300); - req.setRequestHeader("Content-Type", formData.enctype); - req.setRequestHeader("Referer", bugURL + bugID); - req.setRequestHeader("Accept-Charset", formData.acceptCharset); - req.setRequestHeader("Cookie", formData.cookie); - req.onreadystatechange = function(aEvt) { - if (req.readyState == 4) { - if (req.status == 200) { - console.log("Sent form for bug " + bugID); - delete myStorage.forms[bugID]; - } else { - console.error("Sending form for bug " + bugID + "failed!"); - } - } - }; - req.send(formData.data); - } - - if (myStorage.forms.length > 0) { - myStorage.forms.forEach(function(x) { - deserializeAndSend(x); - }); - } -} -*/ -/* Bugzilla functions. */ - -RHBugzillaPage.prototype.ProfessionalProducts = [ - "Red Hat Enterprise Linux", - "Red Hat Enterprise MRG" -]; - -/** - * - */ -RHBugzillaPage.prototype.pasteBacktraceInComments = function() { - // FIXME This paragraph looks suspicous ... what is it? - // Does it belong to this function? - let notedLabel = this.doc.querySelector("label[for='newcc']"); - while (notedLabel.firstChild) { - let node = notedLabel.removeChild(notedLabel.firstChild); - notedLabel.parentNode.insertBefore(node, notedLabel); - } - notedLabel.parentNode.removeChild(notedLabel); - - let abrtQueryURL = "https://bugzilla.redhat.com/buglist.cgi?" - + "cmdtype=dorem&remaction=run&namedcmd=all%20NEW%20abrt%20crashes&sharer_id=74116"; - - let mainTitle = this.doc - .getElementsByClassName("bz_alias_short_desc_container")[0]; - let abrtButton = this.doc.createElement("a"); - abrtButton.setAttribute("accesskey", "a"); - abrtButton.setAttribute("href", abrtQueryURL); - abrtButton.textContent = "Abrt bugs"; - mainTitle.appendChild(abrtButton); - - if (this.idContainsWord("cf_devel_whiteboard", 'btparsed')) { - this.addStuffToTextBox('status_whiteboard', 'btparsed'); - } - - if (!(this.isTriaged() || this.idContainsWord("status_whiteboard", - 'btparsed'))) { - let btAttachments = this.attachments - .filter(function(att, idx, arr) { - return (/backtrace/.test(att[0])); - }); - // TODO we need to go through all backtrace attachments, but - // just the first one will do for now, we would need to do async - // parsing - btAttachments.forEach(function(x) { - attURL = "https://bugzilla.redhat.com/attachment.cgi?id=" - + x[1]; - if (!this.btSnippet) { - let btRaw = hlpr.loadText(attURL, function(ret) { - this.btSnippet = this.parseBacktrace(ret); - if (this.btSnippet) { - this.addStuffToTextBox("comment", this.btSnippet); - this.addStuffToTextBox("status_whiteboard", - "btparsed"); - } - }, this); - } - }, this); - } -}; - -/** - * - */ -RHBugzillaPage.prototype.markBadAttachments = function() { - let badMIMEArray = [ "application/octet-stream", "text/x-log", "undefined" ]; - - let badAttachments = this.attachments.filter(function(att, idx, arr) { - return (hlpr.isInList(att[2], badMIMEArray)); - }); - - if (badAttachments.length > 0) { - let titleElement = this.doc - .getElementsByClassName("bz_alias_short_desc_container")[0]; - titleElement.style.backgroundColor = "olive"; - titleElement.appendChild(this.createFixAllButton(badAttachments)); - badAttachments.forEach(function(x, i, a) { - this.addTextLink(x); - }, this); - } -}; - -/** - * Is this bug a RHEL bug? - * - * @return Boolean true if it is a RHEL bug - */ -RHBugzillaPage.prototype.isEnterprise = function() { - let prod = this.product; - let result = this.ProfessionalProducts.some(function(elem,idx,arr) { - return new RegExp(elem).test(prod); - }); - return result; -}; - -/** - * Find out whether the bug is needed an attention of bugZappers - * - * @return Boolean whether the bug has been triaged or not - */ -RHBugzillaPage.prototype.isTriaged = function() { - // First excceptions - if (this.version > 7 && this.version < 12) { - return this.doc.getElementById("bug_status").value.toUpperCase() !== "NEW"; - } else { // and then the rule - return this.hasKeyword("Triaged"); - } -}; - -/** - * Set branding colours to easily distinguish between Fedora and RHEL bugs - * - * @param brand String with product of the current bug - * @param version String with the version of the bug - * @param its String with the IsueTracker numbers - * @return none - */ -RHBugzillaPage.prototype.setBranding = function() { - let brandColor = {}; - let TriagedColor = {}; - - if (this.isEnterprise()) { - console.log("This is an enterprise bug."); - if (this.its && (this.its.length > 0)) { - brandColor = this.RHITColor; - } else { - brandColor = this.RHColor; - } - } else if (new RegExp("Fedora").test(this.product)) { - console.log("This is NOT an enterprise bug."); - if (this.version == 999) { - brandColor = this.RawhideColor; - } else { - brandColor = this.FedoraColor; - } - } - - // Comment each of the following lines to get only partial branding - this.doc.getElementsByTagName("body")[0].style.background = brandColor - .toString() - + " none"; - this.doc.getElementById("titles").style.background = brandColor.toString() - + " none"; - - // Remove "Bug" from the title of the bug page, so we have more space with - // plenty of tabs - let titleElem = this.doc.getElementsByTagName("title")[0]; - - titleElem.textContent = titleElem.textContent.slice(4); - let bodyTitleParent = this.doc.getElementById("summary_alias_container").parentNode; - let bodyTitleElem = bodyTitleParent.getElementsByTagName("b")[0]; - bodyTitleElem.textContent = bodyTitleElem.textContent.slice(4); - - // Make background-color of the body of bug salmon pink - // for security bugs. - if (this.hasKeyword("Security")) { - this.doc.getElementById("bugzilla-body").style.background = this.SalmonPink - .toString() + ' none'; - } - - // Make it visible whether the bug has been triaged - if (this.isTriaged()) { - this.doc.getElementById("bz_field_status").style.background = brandColor - .lightColor().toString() - + " none"; - } - - // we should make visible whether maintCCAddr is in CCList - if (hlpr.isInList(this.maintCCAddr, this.CCList)) { - let ccEditBoxElem = this.doc.getElementById("cc_edit_area_showhide"); - // ccEditBoxElem.textContent = "*"+ccEditBoxElem.textContent; - ccEditBoxElem.style.color = "navy"; - ccEditBoxElem.style.fontWeight = "bolder"; - ccEditBoxElem.style.textDecoration = "underline"; - } - - // mark suspicious components - let compElems; - let suspiciousComponents = config.gJSONData.configData.suspiciousComponents; - if (suspiciousComponents - && hlpr.isInList(this.component, suspiciousComponents) - && (compElems = this.doc - .getElementById("bz_component_edit_container"))) { - compElems.style.background = "red none"; - } -}; - -/** - * 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 - */ -RHBugzillaPage.prototype.fillInWhiteBoard = function(iLine, driverStr) { - let that = this; - - function groupIDs(manStr, cardStrID) { - let outStr = that.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) { - let soughtID = (manufacturerNo + "," + cardNo).toUpperCase(); - let outList = config.PCI_ID_Array[soughtID]; - if (outList) { - return outList; - } else { - return ""; - } - } - ; - - let outStr = ""; - let cardIDStr = ""; - let cardIDArr = []; - - chipSwitchboard: if (driverStr === "RADEON") { - let cardID = iLine.replace(this.RE.ATIgetID, "$1"); - cardIDArr = checkChipStringFromID("1002", cardID); - if (cardIDArr.length > 0) { - cardIDStr = cardIDArr[0]; - if (cardIDArr[1]) { - optionStr = cardIDArr[1]; - outStr = groupIDs(driverStr, cardIDStr) + "/" + optionStr; - } else { - outStr = groupIDs(driverStr, cardIDStr); - optionStr = ""; - } - } else { - outStr = "**** FULLSTRING: " + iLine; - } - } else { - // Intel Corporation, NVIDIA - cardIDArr = manuChipStrs.filter(function(el, ind, arr) { - return new RegExp(el[0], "i").test(iLine); - }); - if (cardIDArr && (cardIDArr.length > 0)) { - cardIDArr = cardIDArr[0]; - } else { - outStr = iLine; - break chipSwitchboard; - } - // cardIDArr [0] = RE, [1] = ("RADEON","INTEL","NOUVEAU"), [2] = manu - // PCIID - iLine = iLine.replace(new RegExp(cardIDArr[0], "i")).trim(); - // nVidia developers opted-out from grouping - if (driverStr === "INTEL") { - outStr = groupIDs(cardIDArr[1], iLine); - } else { - outStr = iLine; - } - } - this.addStuffToTextBox("status_whiteboard", ("card_" + outStr).trim()); - this.doc.getElementById("chipmagic").style.display = "none"; -}; - -/** - * Get attached Xorg.0.log, parse it and find the value of chip. Does not fill - * the whiteboard itself, just adds button to do so,paramList so that slow - * XMLHttpRequest is done in advance. - * - * @return None - */ -RHBugzillaPage.prototype.fillInChipMagic = function () { - let XorgLogURL = ""; - let XorgLogAttID = ""; - let XorgLogFound = false; - let attURL = "", interestingLine = ""; - let interestingArray = []; - - - // Find out Xorg.0.log attachment URL - this.XorgLogAttList = this.attachments.filter(function (value, index, array) { - // Xorg.0.log must be text, otherwise we cannot parse it - return (/[xX].*log/.test(value[0]) && /text/.test(value[2])); - }); - if (this.XorgLogAttList.length === 0) { - return; - } - - XorgLogAttID = this.XorgLogAttList[this.XorgLogAttListIndex][1]; - attURL = "https://bugzilla.redhat.com/attachment.cgi?id="+XorgLogAttID; - that = this; - - let req = new XMLHttpRequest(); - req.open("GET",attURL,true); - req.onreadystatechange = function (aEvt) { - if (req.readyState == 4) { - if (req.status == 200) { - let ret = req.responseText; - let interestingLineArr = ret.split("\n"). - filter(function (v,i,a) { - return this.RE.Chipset.test(v); - }); - if (interestingLineArr.length >0) { - interestingArray = this.RE.Chipset.exec(interestingLineArr[0]); - interestingLine = interestingArray[2]. - replace(/[\s"]+/g," ").trim(); - // Persuade createNewButton to have mercy and to actually add - // non-default button - this.constantData.chipMagicTrigger = true; - this.chipMagicInterestingLine = interestingLine+"\t"+interestingArray[1] - .toUpperCase(); - this.createNewButton("status_whiteboard", true, "rh-xorg", "chipMagic"); - } - } else { - throw "Getting attachment " + attURL + "failed!"; - } - } - }; - req.send(""); - - this.XorgLogAttListIndex++; -}; - -/** - * Opens a new tab with a query for the given text in the selected component - * - * @param text to be searched for - * @param component String with the component name (maybe latter regexp?) - * @param product (optional) string with the product name, if undefined, - * search in all products - * @return None - * - */ -RHBugzillaPage.prototype.queryInNewTab = function(text, component, product) { - console.log("queryInNewTab / text = " + text); - console.log("queryInNewTab / component = " + component); - console.log("queryInNewTab / product = " + product); - let url = "https://bugzilla.redhat.com/buglist.cgi?query_format=advanced"; - if (product) { - url += "&product=" + product.trim(); - } - if (component) { - url += "&field0-0-0=component&type0-0-0=substring&value0-0-0=" - + component.trim(); - } - // using more complicated query tables here, because they can be more easily - // edited - // for further investigative searches - if (text) { - text = encodeURIComponent(text.trim()); - let searchText = "&field1-0-0=longdesc&type1-0-0=substring&value1-0-0=" - + text - + "&field1-0-1=attach_data.thedata&type1-0-1=substring&value1-0-1=" - + text - + "&field1-0-2=status_whiteboard&type1-0-2=substring&value1-0-2=" - + text; - url += searchText; - jetpack.tabs.open(url); - // Don't do it ... b.m.o is apparently not powerful enough to sustain - // the weight - // of the search - if (false) { - url = "https://bugzilla.mozilla.org/buglist.cgi?query_format=advanced" - + "field0-0-0=product;type0-0-0=regexp;" - + "value0-0-0=thunderbird|firefox|xulrunner" - + searchText.replace("&", ";"); - jetpack.tabs.open(url); - } - } -}; - -/** - * Get the text to search for and prepare other things for the real executive - * function this.queryInNewTab, and run it. - */ -RHBugzillaPage.prototype.queryForSelection = function() { - let text = jetpack.selection.text; - console.log("selection = " + text); - if (!text) { - text = jetpack.clipboard.get(); - console.log("clipboard = " + text); - } - console.log("text = " + text); - if (text) { - this.queryInNewTab(text, this.component); - } -}; - -/** - * Search simple query in the upstream bugzilla appropriate for the component. - */ -RHBugzillaPage.prototype.queryUpstream = function() { - let text = jetpack.selection.text; - if (!text) { - text = jetpack.clipboard.get(); - } - if (text) { - let text = encodeURIComponent(text.trim()); - let queryUpstreamBugsURLArray = this.constantData.queryUpstreamBug; - let url = this.filterByRegexp(queryUpstreamBugsURLArray, this.component); - jetpack.tabs.open(url + text); - } -} - -/** - * - */ -RHBugzillaPage.prototype.sendBugUpstream = function() { - let url = this.filterByRegexp(this.constantData.newUpstreamBug, this - .getOptionValue("component")); - - let ret = jetpack.tabs.open(url); - let that = this; - jetpack.tabs.onReady(function() { - let otherDoc = ret.contentDocument; - let otherElems = otherDoc.forms.namedItem("Create").elements; - otherElems.namedItem("short_desc").value = that.doc - .getElementById("short_desc_nonedit_display").textContent - .trim(); - otherElems.namedItem("comment").value = that.collectComments(); - ret.focus(); - }); -}; - -/** - * Parse the row with the attachment - * - * @param DOM element to be parsed - * @return array with string name of the attachment, integer its id number, - * string of MIME type, integer of size in kilobytes, and the whole - * element itself - */ -RHBugzillaPage.prototype.parseAttachmentLine = function(inElem) { - let MIMEtype = ""; - let size = 0; - - // Skip over obsolete attachments - if (inElem.getElementsByClassName("bz_obsolete").length > 0) { - return ( []); - } - - // getting name of the attachment - let attName = inElem.getElementsByTagName("b")[0].textContent.trim(); - - let aHrefsArr = inElem.getElementsByTagName("a"); - let aHref = Array.filter(aHrefsArr, function(x) { - return x.textContent.trim() == "Details"; - })[0]; - let id = parseInt(aHref.getAttribute("href").replace( - /^.*attachment.cgi\?id=/, ""), 10); - - // getting MIME type and size - let stringArray = inElem.getElementsByClassName("bz_attach_extra_info")[0].textContent - .replace(/[\n ()]+/g, " ").trim().split(", "); - size = parseInt(stringArray[0], 10); - MIMEtype = stringArray[1].split(" ")[0]; - - return [ attName, id, MIMEtype, size, inElem ]; -}; - -/** - * 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 - */ -RHBugzillaPage.prototype.fixElement = function(elem, beforeText, accKey, afterText) { - elem.setAttribute("accesskey", accKey.toLowerCase()); - elem.innerHTML = beforeText + "<b><u>" + accKey + "</u></b>" + afterText; - return elem; -}; - -/** - * 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 - */ -RHBugzillaPage.prototype.getBugzillaName = function(URLhostname) { - let bugzillaID = ""; - if (this.constantData.bugzillalabelNames[URLhostname]) { - bugzillaID = this.constantData.bugzillalabelNames[URLhostname]; - } else { - bugzillaID = ""; - } - return bugzillaID; -}; - -/** - * Callback function for the XMLRPC request - * - * @param ret Object with xmlhttprequest response with attributes: - * + status -- int return code - * + statusText - * + responseHeaders - * + responseText - */ -RHBugzillaPage.prototype.fixingMIMECallBack = function(data, textStatus) { - let that = this; - if (--this.reqCounter <= 0) { - setTimeout(function () { - that.doc.location.reload(true); - }, 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, optional defaults to "text/plain" - * @param email Boolean whether email should be sent to appropriate person; - * option, defaults to false - * - * updateAttachMimeType($data_ref, $username, $password) - * - * Update the attachment mime type of an attachment. The first argument is a - * data hash containing information on the new MIME type and the attachment id - * that you want to act on. - * - * $data_ref = { "attach_id" => "<Attachment ID>", # Attachment ID to perform - * MIME type change on. "mime_type" => "<New MIME Type Value>", # Legal MIME - * type value that you want to change the attachment to. "nomail" => 0, # - * OPTIONAL Flag that is either 1 or 0 if you want email to be sent or not for - * this change }; - * - */ -RHBugzillaPage.prototype.fixAttachById = function(id, type, email) { - if (type === undefined) { - type = "text/plain"; - } - if (email === undefined) { - email = false; - } - - let msg = new XMLRPCMessage("bugzilla.updateAttachMimeType"); - msg.addParameter( { - 'attach_id' : id, - 'mime_type' : type, - 'nomail' : !email - }); - msg.addParameter(this.login); - msg.addParameter(this.password); - - let req = new XMLHttpRequest(); - let that = this; - req.open("POST", XMLRPCurl, true); - req.overrideMimeType("text/xml"); - req.setRequestHeader("Content-type", "text/xml"); - req.onreadystatechange = function(aEvt) { - if (req.readyState == 4) { - if (req.status == 200) { - console.log("Fixing attachment MIME type success!"); - that.fixingMIMECallBack(); - } else { - console.error("Fixing MIME type attachment failed!"); - } - } - }; - req.send(msg.xml()); - this.reqCounter++; -}; - -/** - * Create a button for fixing all bad attachments. - * - * @param list Array of all bad attachmentss - * @return button fixing all bad Attachments - */ -RHBugzillaPage.prototype.createFixAllButton = function(list) { - if (!XMLRPCMessage) { - return; - } - let that = this; - let elem = this.doc.createElement("a"); - elem.setAttribute("href", ""); - elem.setAttribute("accesskey", "f"); - elem.innerHTML = "<b>F</b>ix all"; - elem.addEventListener("click", function() { - Array.forEach(list, function(x) { - this.fixAttachById(x[1]); - }, that); - }, false); - return elem; -}; - -/** - * Add a link to the bad attachment for fixing it. - * - * @param - * <TR> DOM jQuery element with a bad attachment - * @return none - */ -RHBugzillaPage.prototype.addTextLink = function(row) { - let that = this; - let elemS = row[4].getElementsByTagName("td"); - let elem = elemS[elemS.length - 1]; - elem.innerHTML += "<br/><a href=''>Text</a>"; - elem.addEventListener("click", function(x) { - that.fixAttachById(row[1], "text/plain"); - }, false); -}; - -/** - * Add information about the upstream bug upstream, and closing it. - * - * @param evt Event which called this handler - * @return none - */ -RHBugzillaPage.prototype.addClosingUpstream = function() { - let refs = this.doc.getElementById("external_bugs_table") - .getElementsByTagName("tr"); - // that's a bad id, if there is a one. :) - let inputBox = this.doc.getElementById("inputbox"); - let externalBugID = 0; - let wholeURL = ""; - - // Fix missing ID on the external_id SELECT - this.doc.getElementsByName("external_id")[0].setAttribute("id", - "external_id"); - - if (inputBox.value.match(/^http.*/)) { - let helpAElem = this.doc.createElement("a"); - wholeURL = inputBox.value; - helpAElem.setAttribute("href", wholeURL); - let paramsArr = helpAElem.search.replace(/^\?/, '').split('&'); - // get convert URL parameters to an Object - let params = {}, s = []; - paramsArr.forEach(function(par, idx, arr) { - s = par.split('='); - params[s[0]] = s[1]; - }); - if (params.id) { - externalBugID = parseInt(params.id, 10); - inputBox.value = externalBugID; - } - // get host and bugzillaName - let bugzillaName = this.getBugzillaName(helpAElem.hostname); - this.selectOption("external_id", bugzillaName); - } else if (!isNaN(inputBox.value)) { - externalBugID = parseInt(inputBox.value, 10); - let bugzillaHostname = this.doc.getElementById("external_id").value; - wholeURL = bugzillaHostname+"show_bug.cgi?id="+externalBugID; - } else { - // no inputBox.value -- maybe there is an external bug from - // the previous commit? - } - - // FIXME THis is not good, we don't have a feedback for other commands, - // not to be run, if this fails. - - // It is not good to close bug as UPSTREAM, if there is no reference - // to the upstream bug. - if ((externalBugID > 0) || (refs.length > 2)) { - let msgStr = this.commentStrings["sentUpstreamString"]; - msgStr = msgStr.replace("§§§", wholeURL); - this.centralCommandDispatch("comment",msgStr); - this.centralCommandDispatch("status", "CLOSED"); - this.centralCommandDispatch("resolution", "UPSTREAM"); - } else { - console.log("No external bug specified among the External References!"); - } -}; - -RHBugzillaPage.prototype.markBugTriaged = function() { - // Now we lie completely, we just set keyword Triaged, - // this is not just plain ASSIGNED, but - // modified according to - // https://fedoraproject.org/wiki/BugZappers/Meetings/Minutes-2009-Oct-27 - // and - // http://meetbot.fedoraproject.org/fedora-meeting/2009-11-24\ - // /fedora-meeting.2009-11-24-15.11.log.html - // and - // http://meetbot.fedoraproject.org/fedora-meeting/2009-11-24\ - // /fedora-meeting.2009-11-24-15.11.log.html - // for F13 and later, ASSIGNED is "add Triaged keyword" (as well) - // for <F13 it is "add both" (ASSIGNED status and Triaged keyword) - let ver = this.getVersion(); - let assignee = this.getOwner(); - if ((!this.isEnterprise()) && (ver < TriagedDistro)) { - this.selectOption("bug_status", "ASSIGNED"); - } - this.addStuffToTextBox("keywords","Triaged"); -} - -/** - * - */ -RHBugzillaPage.prototype.parseBacktrace = function(ret) { - let splitArray = ret.split("\n"); - let i = 0, ii = splitArray.length; - let outStr = "", curLine = "", numStr = ""; - let lineCounter = 0, endLineNo = 0; - - while (i < ii) { - if (this.RE.signalHandler.test(splitArray[i])) { - break; - } - i++; - } - - if (i < ii) { - lineCounter = parseInt(this.RE.frameNo.exec(splitArray[i])[1], 10); - endLineNo = lineCounter + NumberOfFrames; - curLine = splitArray[i]; - while ((lineCounter < endLineNo) && (curLine.trim().length > 0) - && (i < ii)) { - outStr += curLine + '\n'; - numStr = this.RE.frameNo.exec(curLine); - if (numStr) { - lineCounter = parseInt(numStr[1], 10); - } - i++; - curLine = splitArray[i]; - } - } - return outStr; -}; - - // ///////////////////////////////////////////////////////////////////////////// let config = {}; |