/*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 fileMod = require("file");
var simpleStorage = require("simple-storage");
var preferences = require("preferences-service");
var selection = require("selection");
var prompts = require("prompts");
var tabs = require("tabs");
var Color = require("color").Color;
var bugURL = "https://bugzilla.redhat.com/show_bug.cgi?id=";
// Shared contstants
var TriagedDistro = 13;
exports.TriagedDistro = TriagedDistro;
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"));
}
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.bugNo = util.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();
// 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();
};
/**
* Get the ID of the bug.
*
* @return string
*/
BZPage.prototype.getBugId = function getBugId () {
return util.getBugNo(this.doc.location.href);
};
/**
*
*/
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(/[, ]/));
}
if ("any" in epObject) {
enabledPackages = enabledPackages.concat(epObject.any.split(/[, ]/));
}
} else {
// Default to collecting all comment packages available
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);
};
/**
* 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);
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 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 href="mailto:email"> element diggs out just plain email
* address
*
* @param aElement Element with href attribute or something else
* @return String with the address or null
*
*/
BZPage.prototype.parseMailto = function parseMailto(aElement) {
if (aElement) {
return decodeURI(aElement.getAttribute("href")).
split(":")[1];
}
return null;
};
/**
* Get the current email of the reporter of the bug.
*
* @return string
*/
BZPage.prototype.getReporter = function getReporter () {
var reporterElement = this.doc.
querySelector("#bz_show_bug_column_2 > table .vcard:first-of-type > a");
return this.parseMailto(reporterElement);
};
/**
* 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 getVersion () {
var verStr = this.getOptionValue("version").toLowerCase();
var verNo = 0;
if (/rawhide/.test(verStr)) {
verNo = 999;
} else {
verNo = Number(verStr);
}
return verNo;
};
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;
this.commentsWalker(function(x) {
var email = that.parseMailto(x.getElementsByClassName("vcard")[0]
.getElementsByTagName("a")[0]);
if (new RegExp(that.reporter).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 (kwd.trim().indexOf(str) !== -1);
};
/**
* 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));
};
/**
*
*/
BZPage.prototype.getOptionValue = function getOptionValue (id) {
// Some special bugs don't have version for example
var element = this.doc.getElementById(id);
if (element) {
return element.value;
} else {
console.error("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 setNeedinfoReporter () {
this.clickMouse("needinfo");
this.selectOption("needinfo_role", "reporter");
};
/**
*
*/
BZPage.prototype.getOwner = function getOwner () {
var priorityParent = this.doc.querySelector("label[for~='target_milestone']")
.parentNode.parentNode.parentNode;
var assigneeAElement = priorityParent.querySelector("tr:nth-of-type(1) a.email");
return this.parseMailto(assigneeAElement);
};
/**
* 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;
};
/**
* 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;
};
/**
* 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;
};
/**
* 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;
}
var generateTimeSheetUI = this.doc.createElement("li");
generateTimeSheetUI.innerHTML = "\u00A0-\u00A0<a href='#' id='generateTSButton'>"
+ "Generate TS</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);
var ImportTimeSheetUI = this.doc.createElement("li");
ImportTimeSheetUI.innerHTML = "\u00A0-\u00A0<a href='#' id='importTSButton'>"
+ "Import TS</a>";
additionalButtons.appendChild(ImportTimeSheetUI);
this.doc.getElementById("importTSButton").addEventListener(
"click",
function(evt) {
var otherTS = {}, thisTS = that.log.store;
jsonPaths = prompts.promptFileOpenPicker(that.win);
if (fileMod.exists(jsonPaths)) {
otherTS = JSON.parse(fileMod.read(jsonPaths));
if (otherTS.logs) {
for (var rec in otherTS.logs) {
thisTS[rec] = otherTS.logs[rec];
}
} else {
console.error("This is not a log file!");
}
} else {
console.error("File " + jsonPaths + " doesn't exist!");
}
}, false);
var clearLogsUI = this.doc.createElement("li");
clearLogsUI.innerHTML = "\u00A0-\u00A0<a href='#' id='clearLogs'>"
+ "Clear TS</a>";
additionalButtons.appendChild(clearLogsUI);
var clearLogAElem = this.doc.getElementById("clearLogs");
clearLogAElem.addEventListener("click", function() {
that.log.store = {};
this.style.color = that.log.EmptyLogsColor;
this.style.fontWeight = "normal";
console.log("this.store wiped out!");
}, false);
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";
}
};
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) {
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.component);
}
};
/**
* 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;