blob: b6f02f00efd0f22af83293d48223e7a05b01e0a0 [file] [log] [blame]
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This Source Code Form is "Incompatible With Secondary Licenses", as
* defined by the Mozilla Public License, v. 2.0. */
var Dom = YAHOO.util.Dom;
YAHOO.bugzilla.commentTagging = {
ctag_div : false,
ctag_add : false,
counter : 0,
min_len : 3,
max_len : 24,
tags_by_no: {},
nos_by_tag: {},
current_id: 0,
current_no: -1,
can_edit : false,
pending : {},
label : '',
min_len_error: '',
max_len_error: '',
init : function(can_edit) {
this.can_edit = can_edit;
this.ctag_div = Dom.get('bz_ctag_div');
this.ctag_add = Dom.get('bz_ctag_add');
YAHOO.util.Event.on(this.ctag_add, 'keypress', this.onKeyPress);
YAHOO.util.Event.onDOMReady(function() {
YAHOO.bugzilla.commentTagging.updateCollapseControls();
});
if (!can_edit) return;
var ds = new YAHOO.util.XHRDataSource("jsonrpc.cgi");
ds.connTimeout = 30000;
ds.connMethodPost = true;
ds.connXhrMode = "cancelStaleRequests";
ds.maxCacheEntries = 5;
ds.responseSchema = {
metaFields : { error: "error", jsonRpcId: "id"},
resultsList : "result"
};
var ac = new YAHOO.widget.AutoComplete('bz_ctag_add', 'bz_ctag_autocomp', ds);
ac.maxResultsDisplayed = 7;
ac.generateRequest = function(query) {
query = YAHOO.lang.trim(query);
YAHOO.bugzilla.commentTagging.last_query = query;
YAHOO.bugzilla.commentTagging.counter = YAHOO.bugzilla.commentTagging.counter + 1;
YAHOO.util.Connect.setDefaultPostHeader('application/json', true);
return YAHOO.lang.JSON.stringify({
version: "1.1",
method : "Bug.search_comment_tags",
id : YAHOO.bugzilla.commentTagging.counter,
params : {
Bugzilla_api_token: BUGZILLA.api_token,
query : query,
limit : 10
}
});
};
ac.minQueryLength = this.min_len;
ac.autoHighlight = false;
ac.typeAhead = true;
ac.queryDelay = 0.5;
ac.dataReturnEvent.subscribe(function(type, args) {
args[0].autoHighlight = args[2].length == 1;
});
},
toggle : function(comment_id, comment_no) {
if (!this.ctag_div) return;
var tags_container = Dom.get('ct_' + comment_no);
if (this.current_id == comment_id) {
// hide
this.current_id = 0;
this.current_no = -1;
Dom.addClass(this.ctag_div, 'bz_default_hidden');
this.hideError();
window.focus();
} else {
// show or move
this.rpcRefresh(comment_id, comment_no);
this.current_id = comment_id;
this.current_no = comment_no;
this.ctag_add.value = '';
tags_container.parentNode.insertBefore(this.ctag_div, tags_container);
Dom.removeClass(this.ctag_div, 'bz_default_hidden');
Dom.removeClass(tags_container, 'bz_default_hidden');
var comment = Dom.get('comment_text_' + comment_no);
if (Dom.hasClass(comment, 'collapsed')) {
var link = Dom.get('comment_link_' + comment_no);
expand_comment(link, comment, comment_no);
}
window.setTimeout(function() {
YAHOO.bugzilla.commentTagging.ctag_add.focus();
}, 50);
}
},
hideInput : function() {
if (this.current_id != 0) {
this.toggle(this.current_id, this.current_no);
}
this.hideError();
},
showError : function(comment_id, comment_no, error) {
var bz_ctag_error = Dom.get('bz_ctag_error');
var tags_container = Dom.get('ct_' + comment_no);
tags_container.parentNode.appendChild(bz_ctag_error, tags_container);
Dom.get('bz_ctag_error_msg').innerHTML = YAHOO.lang.escapeHTML(error);
Dom.removeClass(bz_ctag_error, 'bz_default_hidden');
},
hideError : function() {
Dom.addClass('bz_ctag_error', 'bz_default_hidden');
},
onKeyPress : function(evt) {
evt = evt || window.event;
var charCode = evt.charCode || evt.keyCode;
if (evt.keyCode == 27) {
// escape
YAHOO.bugzilla.commentTagging.hideInput();
YAHOO.util.Event.stopEvent(evt);
} else if (evt.keyCode == 13) {
// return
YAHOO.util.Event.stopEvent(evt);
var tags = YAHOO.bugzilla.commentTagging.ctag_add.value.split(/[ ,]/);
var comment_id = YAHOO.bugzilla.commentTagging.current_id;
var comment_no = YAHOO.bugzilla.commentTagging.current_no;
YAHOO.bugzilla.commentTagging.hideInput();
try {
YAHOO.bugzilla.commentTagging.add(comment_id, comment_no, tags);
} catch(e) {
YAHOO.bugzilla.commentTagging.showError(comment_id, comment_no, e.message);
}
}
},
showTags : function(comment_id, comment_no, tags) {
// remove existing tags
var tags_container = Dom.get('ct_' + comment_no);
while (tags_container.hasChildNodes()) {
tags_container.removeChild(tags_container.lastChild);
}
// add tags
if (tags != '') {
if (typeof(tags) == 'string') {
tags = tags.split(',');
}
for (var i = 0, l = tags.length; i < l; i++) {
tags_container.appendChild(this.buildTagHtml(comment_id, comment_no, tags[i]));
}
}
// update tracking array
this.tags_by_no['c' + comment_no] = tags;
this.updateCollapseControls();
},
updateCollapseControls : function() {
var container = Dom.get('comment_tags_collapse_expand_container');
if (!container) return;
// build list of tags
this.nos_by_tag = {};
for (var id in this.tags_by_no) {
if (this.tags_by_no.hasOwnProperty(id)) {
for (var i = 0, l = this.tags_by_no[id].length; i < l; i++) {
var tag = this.tags_by_no[id][i].toLowerCase();
if (!this.nos_by_tag.hasOwnProperty(tag)) {
this.nos_by_tag[tag] = [];
}
this.nos_by_tag[tag].push(id);
}
}
}
var tags = [];
for (var tag in this.nos_by_tag) {
if (this.nos_by_tag.hasOwnProperty(tag)) {
tags.push(tag);
}
}
tags.sort();
if (tags.length) {
var div = document.createElement('div');
div.appendChild(document.createTextNode(this.label));
var ul = document.createElement('ul');
ul.id = 'comment_tags_collapse_expand';
div.appendChild(ul);
for (var i = 0, l = tags.length; i < l; i++) {
var tag = tags[i];
var li = document.createElement('li');
ul.appendChild(li);
var a = document.createElement('a');
li.appendChild(a);
Dom.setAttribute(a, 'href', '#');
YAHOO.util.Event.addListener(a, 'click', function(evt, tag) {
YAHOO.bugzilla.commentTagging.toggleCollapse(tag);
YAHOO.util.Event.stopEvent(evt);
}, tag);
li.appendChild(document.createTextNode(' (' + this.nos_by_tag[tag].length + ')'));
a.innerHTML = YAHOO.lang.escapeHTML(tag);
}
while (container.hasChildNodes()) {
container.removeChild(container.lastChild);
}
container.appendChild(div);
} else {
while (container.hasChildNodes()) {
container.removeChild(container.lastChild);
}
}
},
toggleCollapse : function(tag) {
var nos = this.nos_by_tag[tag];
if (!nos) return;
toggle_all_comments('collapse');
for (var i = 0, l = nos.length; i < l; i++) {
var comment_no = nos[i].match(/\d+$/)[0];
var comment = Dom.get('comment_text_' + comment_no);
var link = Dom.get('comment_link_' + comment_no);
expand_comment(link, comment, comment_no);
}
},
buildTagHtml : function(comment_id, comment_no, tag) {
var el = document.createElement('span');
Dom.setAttribute(el, 'id', 'ct_' + comment_no + '_' + tag);
Dom.addClass(el, 'bz_comment_tag');
if (this.can_edit) {
var a = document.createElement('a');
Dom.setAttribute(a, 'href', '#');
YAHOO.util.Event.addListener(a, 'click', function(evt, args) {
YAHOO.bugzilla.commentTagging.remove(args[0], args[1], args[2])
YAHOO.util.Event.stopEvent(evt);
}, [comment_id, comment_no, tag]);
a.appendChild(document.createTextNode('x'));
el.appendChild(a);
el.appendChild(document.createTextNode("\u00a0"));
}
el.appendChild(document.createTextNode(tag));
return el;
},
add : function(comment_id, comment_no, add_tags) {
// build list of current tags from html
var tags = new Array();
var spans = Dom.getElementsByClassName('bz_comment_tag', undefined, 'ct_' + comment_no);
for (var i = 0, l = spans.length; i < l; i++) {
tags.push(spans[i].textContent.substr(2));
}
// add new tags
var new_tags = new Array();
for (var i = 0, l = add_tags.length; i < l; i++) {
var tag = YAHOO.lang.trim(add_tags[i]);
// validation
if (tag == '')
continue;
if (tag.length < YAHOO.bugzilla.commentTagging.min_len)
throw new Error(this.min_len_error)
if (tag.length > YAHOO.bugzilla.commentTagging.max_len)
throw new Error(this.max_len_error)
// append new tag
if (bz_isValueInArrayIgnoreCase(tags, tag))
continue;
new_tags.push(tag);
tags.push(tag);
}
tags.sort();
// update
this.showTags(comment_id, comment_no, tags);
this.rpcUpdate(comment_id, comment_no, new_tags, undefined);
},
remove : function(comment_id, comment_no, tag) {
var el = Dom.get('ct_' + comment_no + '_' + tag);
if (el) {
el.parentNode.removeChild(el);
this.rpcUpdate(comment_id, comment_no, undefined, [ tag ]);
}
},
// If multiple updates are triggered quickly, overlapping refresh events
// are generated. We ignore all events except the last one.
incPending : function(comment_id) {
if (this.pending['c' + comment_id] == undefined) {
this.pending['c' + comment_id] = 1;
} else {
this.pending['c' + comment_id]++;
}
},
decPending : function(comment_id) {
if (this.pending['c' + comment_id] != undefined)
this.pending['c' + comment_id]--;
},
hasPending : function(comment_id) {
return this.pending['c' + comment_id] != undefined
&& this.pending['c' + comment_id] > 0;
},
rpcRefresh : function(comment_id, comment_no, noRefreshOnError) {
this.incPending(comment_id);
YAHOO.util.Connect.setDefaultPostHeader('application/json', true);
YAHOO.util.Connect.asyncRequest('POST', 'jsonrpc.cgi',
{
success: function(res) {
YAHOO.bugzilla.commentTagging.decPending(comment_id);
data = YAHOO.lang.JSON.parse(res.responseText);
if (data.error) {
YAHOO.bugzilla.commentTagging.handleRpcError(
comment_id, comment_no, data.error.message, noRefreshOnError);
return;
}
if (!YAHOO.bugzilla.commentTagging.hasPending(comment_id))
YAHOO.bugzilla.commentTagging.showTags(
comment_id, comment_no, data.result.comments[comment_id].tags);
},
failure: function(res) {
YAHOO.bugzilla.commentTagging.decPending(comment_id);
YAHOO.bugzilla.commentTagging.handleRpcError(
comment_id, comment_no, res.responseText, noRefreshOnError);
}
},
YAHOO.lang.JSON.stringify({
version: "1.1",
method: 'Bug.comments',
params: {
Bugzilla_api_token: BUGZILLA.api_token,
comment_ids: [ comment_id ],
include_fields: [ 'tags' ]
}
})
);
},
rpcUpdate : function(comment_id, comment_no, add, remove) {
this.incPending(comment_id);
YAHOO.util.Connect.setDefaultPostHeader('application/json', true);
YAHOO.util.Connect.asyncRequest('POST', 'jsonrpc.cgi',
{
success: function(res) {
YAHOO.bugzilla.commentTagging.decPending(comment_id);
data = YAHOO.lang.JSON.parse(res.responseText);
if (data.error) {
YAHOO.bugzilla.commentTagging.handleRpcError(comment_id, comment_no, data.error.message);
return;
}
if (!YAHOO.bugzilla.commentTagging.hasPending(comment_id))
YAHOO.bugzilla.commentTagging.showTags(comment_id, comment_no, data.result);
},
failure: function(res) {
YAHOO.bugzilla.commentTagging.decPending(comment_id);
YAHOO.bugzilla.commentTagging.handleRpcError(comment_id, comment_no, res.responseText);
}
},
YAHOO.lang.JSON.stringify({
version: "1.1",
method: 'Bug.update_comment_tags',
params: {
Bugzilla_api_token: BUGZILLA.api_token,
comment_id: comment_id,
add: add,
remove: remove
}
})
);
},
handleRpcError : function(comment_id, comment_no, message, noRefreshOnError) {
YAHOO.bugzilla.commentTagging.showError(comment_id, comment_no, message);
if (!noRefreshOnError) {
YAHOO.bugzilla.commentTagging.rpcRefresh(comment_id, comment_no, true);
}
}
}