diff options
Diffstat (limited to 'lib/bzpage.js')
-rw-r--r-- | lib/bzpage.js | 1087 |
1 files changed, 0 insertions, 1087 deletions
diff --git a/lib/bzpage.js b/lib/bzpage.js deleted file mode 100644 index cb539dc..0000000 --- a/lib/bzpage.js +++ /dev/null @@ -1,1087 +0,0 @@ -/*jslint forin: true, rhino: true, onevar: false, browser: true, evil: true, laxbreak: true, undef: true, nomen: true, eqeqeq: true, bitwise: true, maxerr: 1000, immed: false, white: false, plusplus: false, regexp: false, undef: false, strict: true */ -// Released under the MIT/X11 license -// http://www.opensource.org/licenses/mit-license.php -"use strict"; -var util = require("util"); -var passUtils = require("passwords"); -var apiUtils = require("api-utils"); -var selfMod = require("self"); -var clip = require("clipboard"); -var preferences = require("preferences-service"); -var selection = require("selection"); -var prompts = require("prompts"); -var Request = require("request").Request; -var tabs = require("tabs"); -var Color = require("color").Color; - -var bugURL = "https://bugzilla.redhat.com/show_bug.cgi?id="; - -// Shared contstants -var NumberOfFrames = 7; -exports.NumberOfFrames = NumberOfFrames; -var BTSPrefNS = "bugzilla-triage.setting."; -exports.BTSPrefNS = BTSPrefNS; -var BTSPassRealm = "BTSXMLRPCPass"; - -// ============================================ - -var NotLoggedinException = function NotLoggedinException (message) { - this.message = message; - this.name = "NotLoggedinException"; -}; - -NotLoggedinException.prototype.toString = function () { - return this.name + ': "' + this.message + '"'; -}; -exports.NotLoggedinException = NotLoggedinException; - -// ==================================================================================== -// BZPage's methods -var BZPage = function BZPage(win, config) { - // 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 - - // initialize dynamic properties - var that = this; - this.win = win; - this.doc = win.document; - this.hostname = this.win.location.hostname; - - // First, preflight check ... if we are not logged in, there - // is nothing we can do. - var logoutLink = Array.some(this.doc.links, function (x) { - return x.search === "?logout=1" ; - }); - if (!logoutLink) { - throw new NotLoggedinException("Not logged in"); - } - - // So, now we know we are logged in, so we can get to - // the real work. - this.packages = this.getInstalledPackages(config); - - if ("commentStrings" in config.gJSONData) { - this.commentStrings = config.gJSONData.commentStrings; - } - - this.constantData = {}; - if ("constantData" in config.gJSONData) { - this.constantData = config.gJSONData.constantData; - this.constantData.queryUpstreamBug = JSON.parse( - selfMod.data.load("queryUpstreamBug.json")); - this.constantData.XMLRPCData = JSON.parse( - selfMod.data.load("XMLRPCdata.json")); - } - - if ("CCmaintainer" in this.constantData) { - this.defBugzillaMaintainerArr = this.constantData.CCmaintainer; - } - - if ("suspiciousComponents" in config.gJSONData.configData) { - this.suspiciousComponents = config.gJSONData.configData.suspiciousComponents; - } - - if ("XorgLogAnalysis" in config.gJSONData.configData) { - this.xorglogAnalysis = config.gJSONData.configData.XorgLogAnalysis; - } - - if ("submitsLogging" in config.gJSONData.configData && - config.gJSONData.configData.submitsLogging) { - this.log = config.logger; - this.setUpLogging(); - } - - if ("killNodes" in config.gJSONData.configData && - this.hostname in config.gJSONData.configData.killNodes) { - var killConf = config.gJSONData.configData.killNodes[this.hostname]; - util.killNodes(this.doc, killConf[0], killConf[1]); - } - - this.setConfigurationButton(); - this.submitHandlerInstalled = false; - - this.login = this.getLogin(); - // XML-RPC password - if (this.hostname in this.constantData.XMLRPCData) { - this.password = this.getPassword(this.login); - } - - this.bugNo = util.getBugNo(this.doc.location.toString()); - - // deal with aliases - if (isNaN(parseInt(this.bugNo, 10)) && this.password) { - this.bugNo = this.getRealBugNo(); - } - - this.title = this.doc.getElementById("short_desc_nonedit_display").textContent; - this.CCList = this.getCCList(); - - // Prepare for query buttons - // element ID brElementPlace_location is later used in JSON files - // Stay with this add_comment element even if RH BZ upgrades, this seems - // to be generally much more stable (even with other bugzillas, e.g. b.gnome.org) - // then some getElementById. - var commentArea = this.doc.getElementsByName("add_comment")[0].parentNode; - if (commentArea) { - var brElementPlacer = commentArea.getElementsByTagName("br"); - brElementPlacer = brElementPlacer[0]; - if (brElementPlacer) { - brElementPlacer.setAttribute("id","brElementPlacer_location"); - brElementPlacer.parentNode.insertBefore(this.doc.createElement("br"), - brElementPlacer); - } - } - - this.checkComments(); - this.generateButtons(); -}; - -/** - * In case URL contains alias, not the real bug number, get the real bug no - * from the XML representation. Sets correct value to this.bugNo. - */ -BZPage.prototype.getRealBugNo = function () { - console.log("We have to deal with bug aliased as " + this.bugNo); - var that = this; - // https://bugzilla.redhat.com/show_bug.cgi?ctype=xml&id=serialWacom - Request({ - url: this.win.location.href+"&ctype=xml", - onComplete: function(response) { - if (response.status === 200) { - var xmlRepr = response.xml; - var bugID = parseInt(xmlRepr.getElementsByTagName("bug_id")[0].textContent, 10); - if (isNaN(bugID)) { - throw new Error("Cannot get bug no. even from XML representation!"); - } - that.bugNo = bugID; - console.log("The real bug no. is " + bugID); - } - } - }).get(); -}; - -/** - * - */ -BZPage.prototype.getInstalledPackages = function getInstalledPackages(cfg) { - var installedPackages = {}; - var enabledPackages = []; - - // Collect enabled packages per hostname (plus default ones) - if (cfg.gJSONData && ("commentPackages" in cfg.gJSONData)) { - if ("enabledPackages" in cfg.gJSONData.configData) { - var epObject = cfg.gJSONData.configData.enabledPackages; - if (this.hostname in epObject) { - enabledPackages = enabledPackages.concat(epObject[this.hostname].split(/[,\s]+/)); - } - if ("any" in epObject) { - enabledPackages = enabledPackages.concat(epObject.any.split(/[,\s]+/)); - } - } - - if ((enabledPackages.length === 1) && (enabledPackages[0] === "all")) { - enabledPackages = []; - for (var key in cfg.gJSONData.commentPackages) { - enabledPackages.push(key); - } - } - - enabledPackages.forEach(function (pkg, idx, arr) { - if (pkg in cfg.gJSONData.commentPackages) { - installedPackages[pkg] = cfg.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 centralCommandDispatch (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": - var 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; - case "queryStringOurBugzilla": - this.queryForSelection(); - 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. - * - * PROBLEM: according to https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference\ - * /Statements/for...in there is no guaranteed order of execution of - * commands (i.e., key, commentObj[key] pairs) in for..in cycle. - * According to https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference\ - * /Operators/Special_Operators/delete_Operator#Cross-browser_issues it seems that - * everywhere except of Internet Explorer this should work well, but waiting - * impatiently when this bite us. - */ -BZPage.prototype.executeCommand = function executeCommand (cmd) { - var cmdArr = cmd.split("//"); - var commentObj = this.packages[cmdArr[0]][cmdArr[1]]; - - for (var key in commentObj) { - this.centralCommandDispatch(key,commentObj[key]); - } -}; - -/** - * Change assignee of the bug - * - * @param newAssignee String with the email address of new assigneeAElement - * or 'default' if the component's default assignee should be used. - * Value null clears "Reset Assignee to default for component" checkbox - * @return none - */ -BZPage.prototype.changeAssignee = function changeAssignee (newAssignee) { - var defAssigneeButton = null; - // Previous assignee should know what's going on in his bug - this.addToCCList(this.owner); - - // Optional value null - if (newAssignee === null) { - this.doc.getElementById("set_default_assignee").removeAttribute( - "checked"); - return ; - } - - if (this.getDefaultAssignee) { - if (newAssignee === "default") { - var 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; - defAssigneeButton = this.doc.getElementById("setDefaultAssignee_btn"); - if (defAssigneeButton) { - 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 addToCommentsDropdown (pkg, cmd) { - var select = this.doc.getElementById("comment_action"); - if (!select) { - var 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 (evt) { - var value = ""; - var valueElement = that.doc.getElementById("comment_action"); - if (valueElement) { - var selIdx = valueElement.selectedIndex; - value = valueElement.options[selIdx].value; - console.log("value = " + value); - } else { - return; - } - that.executeCommand(value); - }, false); - } - - var opt = this.doc.createElement("option"); - opt.value = pkg + "//" + cmd; - opt.textContent = this.packages[pkg][cmd].name; - select.appendChild(opt); -}; - -/** - * Create a A element leadink nowhere, but with listener running a callback on the click - * - * @param id String with a id to be added to the element - * @param text String with a string to be added as a textContent of the element - * @param parent Node which is a parent of the object - * @param callback Function to be called after clicking on the link - * @param params Array with parameters of the callback - * @param Boolean breakBefore if there should be a <br> element before. - * @return none - */ -BZPage.prototype.createDeadLink = function createDeadLink (id, text, parent, callback, params, before, covered, accesskey) { - var that = this; - params = util.valToArray(params); - var locParent = {}; - - // Yes, I want != here, not !== - if (covered != null) { - locParent = this.doc.createElement(covered); - parent.appendChild(locParent); - } else { - locParent = parent; - } - - var newAElem = this.doc.createElement("a"); - newAElem.setAttribute("id", id); - if (accesskey) { - newAElem.setAttribute("accesskey", accesskey); - } - newAElem.setAttribute("href", ""); - newAElem.textContent = text; - - newAElem.addEventListener("click", function(evt) { - callback.apply(that, params); - evt.stopPropagation(); - evt.preventDefault(); - }, false); - - if ((before === "br") || (before === true)) { - locParent.appendChild(this.doc.createElement("br")); - } else if (before === "dash") { - locParent.appendChild(this.doc.createTextNode("\u00A0-\u00A0")); - } - - locParent.appendChild(newAElem); -}; - - -/** - * 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 createNewButton (location, after, pkg, id) { - var that = this; - var cmdObj = this.packages[pkg][id]; - var newId = id + "_btn"; - var label = cmdObj.name; - - // protection against double-firings - if (this.doc.getElementById(newId)) { - console.log("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 ; - } - } - - var 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); - - var originalLocation = this.doc.getElementById(location); - - try { - 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); - } - } catch (e) { - if (e instanceof TypeError) { - console.error("cannot find originalLocation element with id " + location); - } else { - throw e; - } - } -}; - -/** - * - */ -BZPage.prototype.generateButtons = function generateButtons () { - var topRowPosition = "topRowPositionID"; - var bottomRowPosition = "commit"; - - // create anchor for the top toolbar - var commentBox = this.doc.getElementById("comment"); - var brElement = this.doc.createElement("br"); - brElement.setAttribute("id",topRowPosition); - commentBox.parentNode.normalize(); - commentBox.parentNode.insertBefore(brElement, commentBox); - - for (var pkg in this.packages) { - for (var cmdIdx in this.packages[pkg]) { - var 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 - var firstChr = cmdObj.position.charAt(0); - var newId = cmdObj.position.substr(1); - this.createNewButton(newId, firstChr === "+", pkg, cmdIdx); - break; - } - } - } -}; - -BZPage.prototype.setConfigurationButton = function setConfigurationButton () { - var additionalButtons = this.doc.querySelector("#bugzilla-body *.related_actions"); - var configurationButtonUI = this.doc.createElement("li"); - configurationButtonUI.innerHTML = "\u00A0-\u00A0<a href='' id='configurationButton'>" - + "Triage configuration</a>"; - additionalButtons.appendChild(configurationButtonUI); - this.doc.getElementById("configurationButton").addEventListener( - "click", - function(evt) { - var prfNm = BTSPrefNS+"JSONURL"; - var url = preferences.get(prfNm,""); - - var reply = prompts.prompt("New location of JSON configuration file", url); - if (reply) { - preferences.set(prfNm, reply.trim()); - prompts.alert("For now, you should really restart Firefox!"); - } - - evt.stopPropagation(); - evt.preventDefault(); - }, false); -}; - -/* - * From <a> element diggs out just plain email address - * Note that bugzilla.gnome.org doesn't have mailto: url but - * https://bugzilla.gnome.org/page.cgi?id=describeuser.html&login=mcepl%40redhat.com - * - * @param aElement Element with href attribute or something else - * @return String with the address or null - * - */ -BZPage.prototype.parseMailto = function parseMailto(aElement) { - var emailStr = "", hrefStr = ""; - // use url utils - if (aElement) { - hrefStr = decodeURIComponent(aElement.getAttribute("href")); - emailStr = hrefStr.split(":")[1]; - // - if (emailStr === undefined) { - var params = util.getParamsFromURL("https://" + this.hostname + "/" + hrefStr); - emailStr = decodeURI(params.login); - } - return emailStr; - } - return null; -}; - -/** - * Get the current email of the reporter of the bug. - * - * @return string - */ -BZPage.prototype.getReporter = function getReporter () { - var reporterElement = this.getOptionTableCell("bz_show_bug_column_2", "Reported"); - // RH Bugzilla after upgrade to 3.6.2 moved the information to other column - if (!reporterElement) { - reporterElement = this.getOptionTableCell("bz_show_bug_column_1", "Reported", true); - } - // Maemo calls the label "Reporter" and it doesn't have ids on table columns ... TODO(maemo) - - return this.parseMailto(reporterElement); -}; - -BZPage.prototype.getComponent = function getComponent() { - var elem = this.doc.getElementById("component"); - if (elem) { - return elem.value; - } - return null; -}; - - -BZPage.prototype.commentsWalker = function commentsWalker (fce) { - var 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 checkComments () { - var that = this; - var reporterRE = new RegExp(this.getReporter()); - this.commentsWalker(function(x) { - var email = that.parseMailto(x.getElementsByClassName("vcard")[0] - .getElementsByTagName("a")[0]); - if (reporterRE.test(email)) { - x.style.backgroundColor = that.ReporterColor.toString(); - } - }); -}; - -BZPage.prototype.collectComments = function collectComments () { - var outStr = ""; - this.commentsWalker(function(x) { - outStr += x.getElementsByTagName("pre")[0].textContent + "\n"; - }); - return outStr.trim(); -}; - - -/** - * Select option with given value on the <SELECT> element with given id. - * - * Also execute change HTMLEvent, so that the form behaves accordingly. - * - * @param id - * @param label - * @return none - * - */ -BZPage.prototype.selectOption = function selectOption (id, label, fireEvent) { - if (!fireEvent) { - fireEvent = true; - } - var sel = this.doc.getElementById(id); - sel.value = label; - if (fireEvent) { - var intEvent = this.doc.createEvent("HTMLEvents"); - intEvent.initEvent("change", true, true); - sel.dispatchEvent(intEvent); - } -}; - -BZPage.prototype.selectOptionByLabel = function selectOptionByLabel(id, label, fireEvent) { - if (!fireEvent) { - fireEvent = true; - } - var sel = this.doc.getElementById(id); - var labelRE = new RegExp(label.trim()); - var ourOption = Array.filter(sel.options, function (op) { - return op.textContent.trim() === label; - }, this); - - if (ourOption[0]) { - sel.value = ourOption[0].value; - } - - if (fireEvent) { - var 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 clickMouse (targetID) { - var 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); -}; - -/** - * 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 addStuffToTextBox (id, stuff) { - var textBox = this.doc.getElementById(id); - if (textBox.tagName.toLowerCase() === "textarea") { - stuff = textBox.value ? "\n\n" + stuff : stuff; - textBox.value += stuff; - } else { - textBox.value = util.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 removeStuffFromTextBox (id, stuff) { - var changedElement = this.getElementById(id); - changedElement.value = util.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 idContainsWord (id, str) { - var kwd = ""; - try { - 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 (util.isInList(str, kwd.trim().split(/[,\s]+/))); -}; - -/** - * Check for the presence of a keyword - * - * @param str String with the keyword - * @return Boolean - */ -BZPage.prototype.hasKeyword = function hasKeyword (str) { - return (this.idContainsWord('keywords', str)); -}; - -/** - -@return Element with the href attribute containng the information - */ -BZPage.prototype.getOptionTableCell = function getOptionTableCell(tableId, label) { - var cleanLabelRE = /^\s*([^.:]*):?\s*$/; - label = label.trim().replace(cleanLabelRE,"$1").toLowerCase(); - - var rows = this.doc.getElementById(tableId).getElementsByTagName("tr"); - var ourLine = Array.filter(rows, function(row) { - var curLabel = row.getElementsByTagName("td")[0].textContent.toLowerCase(); - curLabel = curLabel.replace(cleanLabelRE,"$1"); - return (curLabel === label); // maybe this could be a RE match instead - }); - - if (ourLine.length > 0) { - return ourLine[0].getElementsByTagName("td")[1]. - getElementsByTagName("a")[0]; - } - return null; -}; - -/** - * 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 setNeedinfoReporter () { - this.clickMouse("needinfo"); - this.selectOption("needinfo_role", "reporter"); -}; - -/** - * - */ -BZPage.prototype.getOwner = function getOwner () { - // TODO(maemo) doesn't work on maemo - var assigneeAElement = this.getOptionTableCell("bz_show_bug_column_1","Assigned To"); - return this.parseMailto(assigneeAElement); -}; - -/** - * 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 getDefaultBugzillaMaintainer (component) { - var address = util.filterByRegexp(this.defBugzillaMaintainerArr, component); - return address; -}; - -/** - * 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 - */ -BZPage.prototype.parseAttachmentLine = function(inElem) { - var MIMEtype = ""; - var size = 0; - - // Skip over obsolete attachments - if (inElem.getElementsByClassName("bz_obsolete").length > 0) { - return ( []); - } - - // getting name of the attachment - // TODO probably could use url.URL object - var attName = inElem.getElementsByTagName("b")[0].textContent.trim(); - - var aHrefsArr = inElem.getElementsByTagName("a"); - var aHref = Array.filter(aHrefsArr, function(x) { - return x.textContent.trim() === "Details"; - })[0]; - var id = parseInt(aHref.getAttribute("href").replace( - /^.*attachment.cgi\?id=/, ""), 10); - - // getting MIME type and size - var 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 ]; -}; - -/** - * 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 getAttachments () { - var outAtts = []; - var atts = this.doc.getElementById("attachment_table") - .getElementsByTagName("tr"); - for ( var i = 1, ii = atts.length - 1; i < ii; i++) { - outAtts.push(this.parseAttachmentLine(atts[i])); - } - return outAtts; -}; - -/** - * Get login of the currently logged-in user. - * - * @return String with the login name of the currently logged-in user - */ -BZPage.prototype.getLogin = function getLogin () { - var lastLIElement = this.doc.querySelector("#header ul.links li:last-of-type"); - var loginArr = lastLIElement.textContent.split("\n"); - var loginStr = loginArr[loginArr.length - 1].trim(); - return loginStr; -}; - -/** - * 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 getPassword (login) { - var passPrompt = "Enter your Bugzilla password for fixing MIME attachment types"; - var switchPrompt = "Do you want to switch off features requiring password completely?"; - var prefName = BTSPrefNS+"withoutPassowrd"; - var domain = this.win.location.protocol + "//" + this.hostname; - - var pass = passUtils.getPassword(login, domain, BTSPassRealm); - // pass === null means no appropriate password in the storage - if (!preferences.get(prefName,false) && (pass === null)) { - var passwordText = prompts.promptPassword(passPrompt); - if (passwordText && passwordText.length > 0) { - passUtils.setLogin(login, passwordText, domain, - BTSPassRealm); - return passwordText; - } else { - var switchOff = prompts.promptYesNoCancel(switchPrompt); - if (switchOff) { - preferences.set(prefName,true); - } - return null; - } - } else { - return pass; - } -}; - -/** - * - */ -BZPage.prototype.setUpLogging = function setUpLogging () { - // Protection against double-call - if (this.doc.getElementById("generateTSButton")) { - return ; - } - - // For adding additional buttons to the top toolbar - var additionalButtons = this.doc.querySelector("#bugzilla-body *.related_actions"); - var that = this; - - // logging all submits for timesheet - if (!this.submitHandlerInstalled) { - this.doc.forms.namedItem("changeform").addEventListener("submit",function (evt) { - var resp = that.log.addLogRecord(that); - if (resp === null) { - evt.stopPropagation(); - evt.preventDefault(); - } - }, false); - this.submitHandlerInstalled = true; - } - - // (id, text, parent, callback, params, before, covered, accesskey) - this.createDeadLink("generateTSButton", "Generate TS", additionalButtons, - function(evt) { - that.log.createBlankPage.call(that.log, "TimeSheet", - that.log.generateTimeSheet); - }, [], "dash", "li"); - - this.createDeadLink("clearLogs", "Clear TS", additionalButtons, - function(evt) { - that.log.clearStore(this); - }, [], "dash", "li"); - - this.createDeadLink("importTSButton", "Import TS", additionalButtons, - function(evt) { - jsonPaths = prompts.promptFileOpenPicker(that.win); - that.log.importOtherStore(jsonPaths, clearLogAElem); - }, [], "dash", "li"); - - var clearLogAElem = this.doc.getElementById("clearLogs"); - if (this.log.isEmpty()) { - clearLogAElem.style.color = this.log.EmptyLogsColor; - clearLogAElem.style.fontWeight = "normal"; - } else { - clearLogAElem.style.color = this.log.FullLogsColor; - clearLogAElem.style.fontWeight = "bolder"; - } -}; - -BZPage.prototype.getSelectionOrClipboard = function getSelectionOrClipboard () { - var text = selection.text; - if (!text) { - text = clip.get(); - } - return text; -}; - -/** - * 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 - * - */ -BZPage.prototype.queryInNewTab = function(text, component, product) { - var urlStr = "https://bugzilla.redhat.com/buglist.cgi?query_format=advanced"; - if (product) { - urlStr += "&product=" + product.trim(); - } - if (component) { - if ("equivalentComponents" in this.constantData) { - var equivCompsArr = this.constantData["equivalentComponents"]. - filter(function (REstr) { - return new RegExp(REstr).test(this.getComponent()); - }, this); - if (equivCompsArr.length > 0) { - component = equivCompsArr[0]; - } - urlStr += "&field0-0-0=component&type0-0-0=regexp&value0-0-0=" - + component.trim(); - } else { - urlStr += "&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()); - var 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; - urlStr += searchText; - tabs.open({ - url: urlStr, - inBackground: true, - onOpen: function (t) { - tabs.activeTab = t; - } - }); - } -}; - -/** - * Get the text to search for and prepare other things for the real executive - * function this.queryInNewTab, and run it. - */ -BZPage.prototype.queryForSelection = function() { - var text = this.getSelectionOrClipboard(); - if (text) { - this.queryInNewTab(text, this.getComponent()); - } -}; - -/** - * 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 addToCCList (who) { - if (!who) { - return ; - } - if (who === "self") { - this.doc.getElementById("addselfcc").checked = true; - } else { - this.clickMouse("cc_edit_area_showhide"); - if (!util.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 getCCList () { - var CCListSelect = this.doc.getElementById("cc"); - var outCCList = []; - if (CCListSelect) { - outCCList = Array.map(CCListSelect.options, function(item) { - return item.value; - }); - } - return outCCList; -}; - -// exports.BZPage = apiUtils.publicConstructor(BZPage); -exports.BZPage = BZPage; |