// Released under the MIT/X11 license
// http://www.opensource.org/licenses/mit-license.php
"use strict";
/**
* 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
*
*/
function selectOption (id, label, fireEvent) {
if (!fireEvent) {
fireEvent = true;
}
var sel = document.getElementById(id);
sel.value = label;
if (fireEvent) {
var intEvent = document.createEvent("HTMLEvents");
intEvent.initEvent("change", true, true);
sel.dispatchEvent(intEvent);
}
}
function selectOptionByLabel(id, label, fireEvent) {
if (!fireEvent) {
fireEvent = true;
}
var sel = document.getElementById(id);
var labelRE = new RegExp(label.trim());
var ourOption = Array.filter(sel.options, function (op) {
return op.textContent.trim() === label;
});
if (ourOption[0]) {
sel.value = ourOption[0].value;
}
if (fireEvent) {
var intEvent = document.createEvent("HTMLEvents");
intEvent.initEvent("change", true, true);
sel.dispatchEvent(intEvent);
}
}
/**
* 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
*/
function addStuffToTextBox (id, stuff) {
var saveFocus = document.activeElement;
var textBox = document.getElementById(id);
if (textBox.tagName.toLowerCase() === "textarea") {
stuff = textBox.value ? "\n\n" + stuff : stuff;
textBox.value += stuff;
}
else {
textBox.value = addCSVValue(textBox.value,stuff);
}
saveFocus.focus();
}
/**
* 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
*/
function removeStuffFromTextBox (id, stuff) {
var changedElement = document.getElementById(id);
changedElement.value = 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?
*/
function idContainsWord (id, str) {
var kwd = "";
try {
kwd = document.getElementById(id).value;
} catch (e) {
// For those who don't have particular element at all or if it is empty
return false;
}
return (isInList(str, kwd.trim().split(/[,\s]+/)));
}
/**
* Check for the presence of a keyword
*
* @param str
* String with the keyword
* @return Boolean
*/
function hasKeyword (str) {
return (idContainsWord('keywords', str));
}
/**
* 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]
*/
function setNeedinfoReporter () {
clickMouse("needinfo");
selectOption("needinfo_role", "reporter");
}
/**
*
*/
function getOwner () {
// TODO(maemo) doesn't work on maemo
var assigneeAElement = getOptionTableCell("bz_show_bug_column_1","Assigned To");
return 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
*/
function getDefaultBugzillaMaintainer (component) {
return filterByRegexp(constantData.defBugzillaMaintainerArr, component);
}
/**
* dd
*
* @return Element with the href attribute containng the information
*/
function getOptionTableCell(tableId, label) {
var cleanLabelRE = new RegExp("^\\s*([^.:]*):?\\s*$");
label = label.trim().replace(cleanLabelRE,"$1").toLowerCase();
var rows = document.getElementById(tableId).getElementsByTagName("tr");
var ourLine = Array.filter(rows, function(row) {
var curLabelElems = row.getElementsByTagName("td");
if (curLabelElems.length > 0) {
var curLabel = curLabelElems[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;
}
/**
* 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
*/
function createNewButton (location, after, cmdObj) {
try {
var newId = cmdObj.name.toLowerCase().replace(/[^a-z0-9]+/,"","g") + "_btn";
} catch (e) {
console.error("createNewButton : e = " + e +
"\ncreateNewButton : cmdObj.toSource() = " +
cmdObj.toSource());
}
// protection against double-firings
if (document.getElementById(newId)) {
console.log("Element with id " + newId + " already exists!");
return ;
}
var newButton = document.createElement("input");
newButton.setAttribute("id", newId);
newButton.setAttribute("type", "button");
newButton.value = cmdObj.name;
newButton.addEventListener("click", function(evt) {
executeCommand(cmdObj);
}, false);
var originalLocation = document.getElementById(location);
try {
if (after) {
originalLocation.parentNode.insertBefore(newButton,
originalLocation.nextSibling);
originalLocation.parentNode.insertBefore(document
.createTextNode("\u00A0"), newButton);
}
else {
originalLocation.parentNode.insertBefore(newButton, originalLocation);
originalLocation.parentNode.insertBefore(document
.createTextNode("\u00A0"), originalLocation);
}
} catch (e) {
if (e instanceof TypeError) {
console.error("cannot find originalLocation element with id " + location);
}
else {
throw e;
}
}
}
/**
* Get the current title of the bug
*
* @return string
*/
function getSummary() {
return document.getElementById("short_desc_nonedit_display").textContent;
}
/**
* Get the current title of the bug
*
* @return string
*/
function getSeverity() {
return document.getElementById("bug_severity").value;
}
/**
* Get the current email of the reporter of the bug.
*
* @return string
*/
function getReporter () {
var reporterElement = getOptionTableCell("bz_show_bug_column_2", "Reported");
// RH Bugzilla after upgrade to 3.6.2 moved the information to other column
if (!reporterElement) {
reporterElement = 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 parseMailto(reporterElement);
}
function getComponent() {
var elem = document.getElementById("component");
if (elem) {
return elem.value;
}
return null;
}
function getProduct() {
var elem = document.getElementById("product");
if (elem) {
return elem.value;
}
return null;
}
function commentsWalker (fce) {
var comments = document.getElementById("comments").
getElementsByClassName("bz_comment");
Array.forEach(comments, function(item) {
fce(item);
});
}
/**
* 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
*
* TODO error handling is missing ... it's bleee
*/
function parseAttachmentLine(inElem) {
var MIMEtype = "";
var size = 0;
// Skip over obsolete attachments
if (inElem.getElementsByClassName("bz_obsolete").length > 0) {
return ([]);
}
// getting name of the attachment
var attName = inElem.getElementsByTagName("b")[0].textContent.trim();
// TODO probably could use url.URL object
var aHrefsArr = inElem.getElementsByTagName("a");
var aHref = Array.filter(aHrefsArr, function(x) {
return x.textContent.trim() === "Details";
})[0];
var id = parseURL(aHref.getAttribute("href")).params.id;
// 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
*/
function getAttachments () {
var outAtts = [];
var atts = document.getElementById("attachment_table").
getElementsByTagName("tr");
for ( var i = 1, ii = atts.length - 1; i < ii; i++) {
outAtts.push(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
*/
function getLogin () {
var lastLIElement = document.querySelector("#header ul.links li:last-of-type");
var loginArr = lastLIElement.textContent.split("\n");
var loginStr = loginArr[loginArr.length - 1].trim();
return loginStr;
}
/**
* 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
*/
function addToCCList (who) {
if (!who) {
return ;
}
if (who === "self") {
document.getElementById("addselfcc").checked = true;
}
else {
clickMouse("cc_edit_area_showhide");
if (!isInList(who, getCCList())) {
addStuffToTextBox("newcc",who);
}
}
}
/**
* a collect a list of emails on CC list
*
* @return Array with email addresses as Strings.
*/
function getCCList () {
var CCListSelect = document.getElementById("cc");
var outCCList = [];
if (CCListSelect) {
outCCList = Array.map(CCListSelect.options, function(item) {
return item.value;
});
}
return outCCList;
}
/**
* remove elements from the page based on their IDs
*
* @param doc
* Document object
* @param target
* Array with querySelector parameters
* @param remove
* Boolean indicating whether the node should be actually removed or
* just hidden.
* @return none TODO remove parameter could be replaced by function which would
* do actual activity.
*/
function killNodes(doc, target, remove) {
var victimElements = [];
if (target.forEach) {
target.forEach(function(x) {
var targetNode = doc.querySelector(x);
if (targetNode) {
if (remove) {
victimElements.push([x,targetNode]);
}
else {
targetNode.style.display = "none";
}
}
});
}
var elem = {};
// Don't run victimElements.forEach here as we are effectively
// removing its members.
for(var i = 0, ii = victimElements.length; i < ii; i++) {
elem = victimElements[i];
try {
elem[1].parentNode.removeChild(elem[1]);
}
catch (e if e instanceof TypeError) {
console.error("Cannot remove: " + elem[0]);
}
}
}
/**
* Is this bug a RHEL bug?
*
* @return Boolean true if it is a RHEL bug
*/
function isEnterprise() {
var result = ProfessionalProducts.some(function(elem,idx,arr) {
return new RegExp(elem).test(getProduct());
});
return result;
}
/**
* Find out whether the bug is needed an attention of bugZappers
*
* @return Boolean whether the bug has been triaged or not
*/
function isTriaged() {
return hasKeyword("Triaged");
}
/**
* Return string with the ID for the external_id SELECT for external bugzilla
*
* @param URLhostname
* String hostname of the external bugzilla
* @return String with the string for the external_id SELECT
*/
function getBugzillaName(URLhostname, bzLabelNames) {
var bugzillaID = "";
if (bzLabelNames[URLhostname]) {
bugzillaID = bzLabelNames[URLhostname];
}
else {
bugzillaID = "";
}
return bugzillaID;
}
/**
*
* original 2011-03-30 15:49:27 EDT
*/
function parseBZCommentDate(dateString) {
var tZone = {
"EDT": 4,
"EST": 5
};
var dateArr = dateString.trim().split(/\s+/);
var timeZoneOffset = tZone[dateArr[2]] -
((new Date()).getTimezoneOffset())/60;
var dArr = dateArr[0].split("-");
var tArr = dateArr[1].split(":");
var dayObj = new Date(+dArr[0],+dArr[1]-1,+dArr[2],
+tArr[0]+timeZoneOffset,+tArr[1],+tArr[2],0);
return dayObj;
};