")
.addClass("customizationList")
.attr("sListID", $(this).attr("sListID"))
.appendTo(divTarget);
loadCustomizationList(divList);
});
};
var processEditRulesPopups = function() {
$("span.editRules")
.click(function() {
var permBlock = $(this).next(".permissionBlock");
permBlock.show();
$(this).hide();
fixDroplists(permBlock);
});
};
var invalidate = function() {
api.setting("build", 1 + (parseInt(api.setting("build")) || 0));
};
var fixDroplists = function(target) {
// Update all the droplists
$(target).find("select").each(function() { DropListControl.refresh(this); });
};
var fixHtml = function(target) {
var jActionItems =
$(target)
.find("a,input[type=submit]");
$.each(["sView", "sAction"], function(ix, attr) {
jActionItems
.filter("[" + attr + "]")
.click(function() {
var data = {};
data[attr] = $(this).attr(attr);
var srgParams = $(this).attr("srgParams");
if (srgParams != null && srgParams.length > 0) {
$.each(srgParams.split(","), function(ix, el) {
data[el] = $("#" + el).val();
});
}
Cust.loadPage(data);
})
.filter("[sidRequiredCheckbox]")
.attr("disabled", "disabled")
.each(function() {
var btn = this;
var cb = $("input[type='checkbox']").filter("[id='" + $(this).attr("sidRequiredCheckbox") + "']");
cb.change(function() {
if (cb.is(":checked")) {
$(btn).removeAttr("disabled");
}
else {
$(btn).attr("disabled", "disabled");
}
});
});
});
fixDroplists(target);
};
var activatePage = function(target) {
fixHtml(target);
processPermissionBlocks();
processCustomizationLists();
processListSelectors();
processEditRulesPopups();
$("#sCust").bind("change keydown", function() { $("#CustomizationErrors").hide(); });
$("span.toggleEnableCust").click(function() {
var target = this;
$.post(sUrl,
wrapArgs({ sAction: "toggleEnableCust", ixCust: $(this).attr("ixCust") }),
function(data) {
if (data.fSuccess) {
$(target).text(data.fEnabled ? "Yes" : "No");
}
if (data.fEnabled) {
Cust.showMessage("Newly enabled customizations will take effect when you
refresh the page", true);
}
},
"json"
);
});
};
var Cust = {
init: function() {
$(window).bind("hashchange", function(e) {
var sNewHash = $.param.fragment();
if (sNewHash != sCurrentHash) {
Cust.loadPage($.deparam(sNewHash));
}
});
if (window.location.hash) {
$(window).trigger("hashchange");
}
else {
$("#Customizations").each(function(_, element) {
activatePage(element);
});
}
invalidate(); // TODO: Be more specific about when this happens
},
showError: function(sError) {
$("#CustomizationErrors")
.removeClass("message")
.addClass("error")
.text(sError)
.show()
.yft();
},
showMessage: function(sMessage, fAllowHtml) {
var divErrors = $("#CustomizationErrors");
var fRepeat = false;
divErrors
.removeClass("error")
.addClass("message");
if (fAllowHtml) {
fRepeat = (sMessage == divErrors.html());
divErrors.html(sMessage);
}
else {
fRepeat = (sMessage == divErrors.text());
divErrors.text(sMessage);
}
divErrors
.show();
if (!fRepeat) {
divErrors.yft();
}
},
loadPage: function(args, target, fNoHistory) {
if (args.sAction) {
if (args.sAction == "back") {
window.history.back();
} else {
$.post(sUrl,
wrapArgs(args),
function(data) {
if (data.fSuccess) {
if (data.redirect) {
Cust.loadPage(data.redirect);
}
if (data.sMessage) {
Cust.showMessage(data.sMessage);
}
if (args.sAction == "apply") {
$("div.requiresApply")
.removeClass("requiresApply")
.each(function() {
$("#ixCust").val(data.ixCust);
$(this).find("[ixCust]").attr("ixCust", data.ixCust);
$(this).find("[ixActTargetValue]").attr("ixActTargetValue", data.ixCust);
})
.show();
}
}
else {
Cust.showError(data.sError);
}
},
"json"
);
}
} else {
if (!fNoHistory) {
sCurrentHash = $.param(args);
window.navigation.navigate(sCurrentHash, 'hash');
}
$("#CustomizationErrors").hide();
$(target || "#Customizations")
.load("?", wrapArgs(args), function() {
activatePage(this);
});
}
}
};
Cust.init();
})(new BugMonkey.api("BugMonkey"));
});
/*
* jQuery BBQ: Back Button & Query Library - v1.2.1 - 2/17/2010
* http://benalman.com/projects/jquery-bbq-plugin/
*
* Copyright (c) 2010 "Cowboy" Ben Alman
* Dual licensed under the MIT and GPL licenses.
* http://benalman.com/about/license/
*/
(function($, p) { var i, m = Array.prototype.slice, r = decodeURIComponent, a = $.param, c, l, v, b = $.bbq = $.bbq || {}, q, u, j, e = $.event.special, d = "hashchange", A = "querystring", D = "fragment", y = "elemUrlAttr", g = "location", k = "href", t = "src", x = /^.*\?|#.*$/g, w = /^.*\#/, h, C = {}; function E(F) { return typeof F === "string" } function B(G) { var F = m.call(arguments, 1); return function() { return G.apply(this, F.concat(m.call(arguments))) } } function n(F) { return F.replace(/^[^#]*#?(.*)$/, "$1") } function o(F) { return F.replace(/(?:^[^?#]*\?([^#]*).*$)?.*/, "$1") } function f(H, M, F, I, G) { var O, L, K, N, J; if (I !== i) { K = F.match(H ? /^([^#]*)\#?(.*)$/ : /^([^#?]*)\??([^#]*)(#?.*)/); J = K[3] || ""; if (G === 2 && E(I)) { L = I.replace(H ? w : x, "") } else { N = l(K[2]); I = E(I) ? l[H ? D : A](I) : I; L = G === 2 ? I : G === 1 ? $.extend({}, I, N) : $.extend({}, N, I); L = a(L); if (H) { L = L.replace(h, r) } } O = K[1] + (H ? "#" : L || !K[1] ? "?" : "") + L + J } else { O = M(F !== i ? F : p[g][k]) } return O } a[A] = B(f, 0, o); a[D] = c = B(f, 1, n); c.noEscape = function(G) { G = G || ""; var F = $.map(G.split(""), encodeURIComponent); h = new RegExp(F.join("|"), "g") }; c.noEscape(",/"); $.deparam = l = function(I, F) { var H = {}, G = { "true": !0, "false": !1, "null": null }; $.each(I.replace(/\+/g, " ").split("&"), function(L, Q) { var K = Q.split("="), P = r(K[0]), J, O = H, M = 0, R = P.split("]["), N = R.length - 1; if (/\[/.test(R[0]) && /\]$/.test(R[N])) { R[N] = R[N].replace(/\]$/, ""); R = R.shift().split("[").concat(R); N = R.length - 1 } else { N = 0 } if (K.length === 2) { J = r(K[1]); if (F) { J = J && !isNaN(J) ? +J : J === "undefined" ? i : G[J] !== i ? G[J] : J } if (N) { for (; M <= N; M++) { P = R[M] === "" ? O.length : R[M]; O = O[P] = M < N ? O[P] || (R[M + 1] && isNaN(R[M + 1]) ? {} : []) : J } } else { if ($.isArray(H[P])) { H[P].push(J) } else { if (H[P] !== i) { H[P] = [H[P], J] } else { H[P] = J } } } } else { if (P) { H[P] = F ? i : "" } } }); return H }; function z(H, F, G) { if (F === i || typeof F === "boolean") { G = F; F = a[H ? D : A]() } else { F = E(F) ? F.replace(H ? w : x, "") : F } return l(F, G) } l[A] = B(z, 0); l[D] = v = B(z, 1); $[y] || ($[y] = function(F) { return $.extend(C, F) })({ a: k, base: k, iframe: t, img: t, input: t, form: "action", link: k, script: t }); j = $[y]; function s(I, G, H, F) { if (!E(H) && typeof H !== "object") { F = H; H = G; G = i } return this.each(function() { var L = $(this), J = G || j()[(this.nodeName || "").toLowerCase()] || "", K = J && L.attr(J) || ""; L.attr(J, a[I](K, H, F)) }) } $.fn[A] = B(s, A); $.fn[D] = B(s, D); b.pushState = q = function(I, F) { if (E(I) && /^#/.test(I) && F === i) { F = 2 } var H = I !== i, G = c(p[g][k], H ? I : {}, H ? F : 2); p[g][k] = G + (/#/.test(G) ? "" : "#") }; b.getState = u = function(F, G) { return F === i || typeof F === "boolean" ? v(F) : v(G)[F] }; b.removeState = function(F) { var G = {}; if (F !== i) { G = u(); $.each($.isArray(F) ? F : arguments, function(I, H) { delete G[H] }) } q(G, 2) }; e[d] = $.extend(e[d], { add: function(F) { var H; function G(J) { var I = J[D] = c(); J.getState = function(K, L) { return K === i || typeof K === "boolean" ? l(I, K) : l(I, L)[K] }; H.apply(this, arguments) } if ($.isFunction(F)) { H = F; return G } else { H = F.handler; F.handler = G } } }) })(jQuery, this);
/*
* jQuery hashchange event - v1.2 - 2/11/2010
* http://benalman.com/projects/jquery-hashchange-plugin/
*
* Copyright (c) 2010 "Cowboy" Ben Alman
* Dual licensed under the MIT and GPL licenses.
* http://benalman.com/about/license/
*/
(function($, i, b) { var j, k = $.event.special, c = "location", d = "hashchange", l = "href", f = $.browser, g = document.documentMode, h = f.msie && (g === b || g < 8), e = "on" + d in i && !h; function a(m) { m = m || i[c][l]; return m.replace(/^[^#]*#?(.*)$/, "$1") } $[d + "Delay"] = 100; k[d] = $.extend(k[d], { setup: function() { if (e) { return false } $(j.start) }, teardown: function() { if (e) { return false } $(j.stop) } }); j = (function() { var m = {}, r, n, o, q; function p() { o = q = function(s) { return s }; if (h) { n = $('
').hide().insertAfter("body")[0].contentWindow; q = function() { return a(n.document[c][l]) }; o = function(u, s) { if (u !== s) { var t = n.document; t.open().close(); t[c].hash = "#" + u } }; o(a()) } } m.start = function() { if (r) { return } var t = a(); o || p(); (function s() { var v = a(), u = q(t); if (v !== t) { o(t = v, u); $(i).trigger(d) } else { if (u !== t) { i[c][l] = i[c][l].replace(/#.*/, "") + "#" + u } } r = setTimeout(s, $[d + "Delay"]) })() }; m.stop = function() { if (!n) { r && clearTimeout(r); r = 0 } }; return m })() })(jQuery, this);
/* Globals
* We've generated the following variables to help us out:
* var CaseEventEdit_sPluginPrefix
* var CaseEventEdit_sActionToken
* var CaseEventEdit_sRawPageURL
* var CaseEventEdit_sHTMLIconAttach
* var CaseEventEdit_sHTMLIconTrash
* var CaseEventEdit_sHTMLIconLoading
* var CaseEventEdit_fBulkEdit
*/
//Bulk Edit Disabler:
//If I'm bulk-editing, get rid of the edit icons.
//All sorts of crazy stuff can happen, so we must do this continuously.
//ATM, this must be done in Javascript.
$(document).ready(function() {
if (typeof(CaseEventEdit_fBulkEdit) != "undefined" && CaseEventEdit_fBulkEdit) {
setInterval(function() {
$('[id^="CaseEventEditIcon"]', '#bugEventHistory').remove();
$('[id^="CaseEventEditIcon"]', '#BugEvents').remove();
}, 50);
}
});
//CaseEventEdit Class:
var CaseEventEdit = CaseEventEdit ? CaseEventEdit : function() {
//Private members:
var Historian = ConstructHistorian();
var Editor = ConstructEditor();
var hashBEToEdit = {}; //dictionary of bugevent : ixedit.
var sREQUESTFAIL = 'Server not responding... Refreshing this page might help.';
//Public accessors:
var members = {
MakeEditable: Editor.MakeEditable,
Edit: Editor.EditCaseEvent,
ToggleHistory: Historian.ToggleHistory,
ShowHistory: Historian.ShowHistory,
HideHistory: Historian.HideHistory,
RefreshHistoryFromSelectObj: Historian.RefreshHistoryFromSelectObj,
ScrollTo: ScrollTo,
hash: hashBEToEdit,
FixImages : FixImages
};
//Utilities:
function Prefix(s) {
return '&' + CaseEventEdit_sPluginPrefix + s;
}
function ScrollTo(sID) {
try {
if (!CaseEventEdit_fBulkEdit) {
$(window).scrollTop($('#' + sID).position().top);
}
else {
$('#' + sID).parents('.itemBody').scrollTop($('#' + sID).position().top);
}
}
catch (e) {
}
}
function FixImages() {
try {
shrinkImagesToFit();
}
catch (e) {
}
}
function ParseData(sResponse) {
var o = $(sResponse);
if ($.browser.msie) {
return o.attr('sData'); //IE is happy to read the attributes, but won't read .text() or xml.
}
return o.text(); //FF/Chrome are happy to read xml or preserve spaces via .text(), but won't respect spaces in attributes.
}
function GetFormat(sResponse) {
var o = $(sResponse);
return o.attr("sFormat");
}
//Editor Constructor
function ConstructEditor() {
//Public members:
var members = {
MakeEditable: MakeEditable,
EditCaseEvent: EditCaseEvent,
GetInsertionPoint: GetInsertionPoint
};
//Private members:
var sSAVING = 'Saving...';
var hashForceRefresh = {};
var hashAttach = {}; //dictionary of bugevent : { sFileName : ixFile }
var hashFileToAttach = {}; //Dictionary of ixFile -> ixAttachment
//Uploader class
var Uploader = function() {
var c = 0;
var rgFxn = {};
var cRgFxn = 0;
return {
UploadStart: function() { c++; },
UploadComplete: function() {
c--;
if (c === 0) {
for (var ix = 0; ix < cRgFxn; ix++) {
rgFxn[ix]();
}
cRgFxn = 0;
rgFxn = {};
}
},
OnNotUploading: function(fxn) {
if (c === 0) {
fxn(); //If all uploads are complete, callback immediately.
}
else {
rgFxn[cRgFxn++] = fxn; //else, enqueue
}
}
};
} ();
//Function with private variable
var GetUID = function() {
var cUID = 1; // Start at 1, since 0 == false, which can suck.
return function() { return cUID++; };
} ();
function updateHashBEToEdit() {
$(".caseEventEditIxEditData").each(function() {
var me = $(this);
var ixBE = me.data("ixbugevent");
var ixEdit = me.data("ixedit");
if (hashBEToEdit[ixBE] === undefined) {
hashBEToEdit[ixBE] = ixEdit;
}
else {
hashBEToEdit[ixBE] = Math.max(hashBEToEdit[ixBE], ixEdit);
}
});
}
$(function() { updateHashBEToEdit(); });
function MakeEditable(ixBugEvent) {
//This function will apply markup to a bugevent body so that it becomes editable.
var body = $('#bugeventBody_' + ixBugEvent);
//Place an empty span before the body text which we can use as an insertion point.
body.before('
');
//Initialize its attachment hash.
hashAttach[ixBugEvent] = {};
}
function SetAttachmentButtonText(ixBugEvent, sText) {
$('#BugEventAttachText' + ixBugEvent).text(sText);
}
function RemoveFile(ixFile, ixBugEvent) {
var divFile = $('#CaseEventEdit_File' + ixFile);
var sFile = divFile.attr('value');
var cRemaining = $('#BugEventAttach' + ixBugEvent).children().length;
divFile.stop().hide('blind', {}, 100, function() { $(this).remove(); });
hashAttach[ixBugEvent][sFile] = undefined;
if (cRemaining === 1) {
//If we just removed the last attachment, revert our attachment text.
SetAttachmentButtonText(ixBugEvent, 'Attach a file');
}
}
function AddAttachment(ixBugEvent, sFile) {
var spanAttach = $('#BugEventAttach' + ixBugEvent);
if (sFile != '') {
if (hashAttach[ixBugEvent] !== undefined && hashAttach[ixBugEvent][sFile] !== undefined) {
//We already have this file.
$('#CaseEventEdit_File' + hashAttach[ixBugEvent][sFile]).stop(true, true).effect('highlight', {}, 2000);
return false;
}
var ixFile = GetUID();
var aRemove = $('
' + CaseEventEdit_sHTMLIconTrash + '');
aRemove.click(function() { RemoveFile(ixFile, ixBugEvent); });
var divFile = $('
' + CaseEventEdit_sHTMLIconLoading + '' + sFile + '
');
divFile.append(aRemove);
spanAttach.append(divFile);
SetAttachmentButtonText(ixBugEvent, 'Attach another file');
if (hashAttach[ixBugEvent] === undefined) {
hashAttach[ixBugEvent] = {};
}
hashAttach[ixBugEvent][sFile] = ixFile;
Uploader.UploadStart();
return true;
}
}
function SetEditSaving(ixBugEvent, fSaving) {
if (fSaving) {
$('#TextSaveEditEvent' + ixBugEvent).attr({ value: sSAVING, disabled: true });
$('#TextCancelEditEvent' + ixBugEvent).attr({ disabled: true });
}
else {
$('#TextSaveEditEvent' + ixBugEvent).attr({ value: 'OK', disabled: false });
$('#TextCancelEditEvent' + ixBugEvent).attr({ disabled: false });
}
}
function IsEditSaving(ixBugEvent) {
return ($('#TextSaveEditEvent' + ixBugEvent).attr('value') == sSAVING);
}
function GetInsertionPoint(ixBugEvent) {
var ip = $('#CaseEventEditInsertionPoint' + ixBugEvent);
if (ip.length == 0) {
MakeEditable(ixBugEvent);
ip = $('#CaseEventEditInsertionPoint' + ixBugEvent);
}
return ip;
}
function DisableEditor(ixBugEvent) {
$('#BugEventTextArea' + ixBugEvent).richtextarea({ enabled: false });
}
/****************************
* Editing Ajaxy functions: *
****************************/
function EditCaseEvent(ixBugEvent) {
if (CaseEventEdit_fBulkEdit) {
$('#CaseEventEditIcon' + ixBugEvent).after('
Cannot edit events while Bulk Editing cases
').remove();
return;
}
var oInsertionPoint = GetInsertionPoint(ixBugEvent);
if (oInsertionPoint.attr('editing') == 'true') {
return;
}
//Mark us as editing.
oInsertionPoint.attr('editing', 'true');
//Hide the 'edit' icon and show the throbber.
var icons = $('#CaseEventEditIcon' + ixBugEvent).children();
$(icons[0]).hide();
$(icons[1]).show();
var fxn = function(sHTML, status) {
var sData = ParseData(sHTML);
var sErr = '';
var fOK = $(sHTML).attr('fOK') == 1;
if (!fOK) {
//Couldn't load the case.
sData = ''; //Don't say 'undefined'.
sErr = $(sHTML).attr('sMsg');
if (!sErr) { sErr = sREQUESTFAIL; }
}
var sPaddingButNotInIE = $.browser.msie ? '' : 'style = "padding-right:0.4em;"';
var sAttachmentButton = '
';
var dialog = '
';
dialog += '
Edit Case Event
' + sErr + '';
dialog += '
';
dialog += ' ';
dialog += '
';
$(dialog).hide().insertAfter(oInsertionPoint).children('#BugEventTextArea' + ixBugEvent);
//Set the textarea's data. We have to do this after the preceeding DOM insertion, else it mysteriously fails.
var textarea = $('#BugEventTextArea' + ixBugEvent);
textarea.val(sData);
//Enable snippets for this textarea (Only allowed in FB8+)
textarea.keypress(function(evt) {
fb.snippet.handleSnippetTargetKeypress(this, evt)
});
var fHtml = (GetFormat(sHTML) === "html");
// Hook up the editor used to edit case events
textarea.richtextarea({
config: {
FBformsubmit_targetSelector: "#TextSaveEditEvent" + ixBugEvent
},
enabled: fHtml,
containsHtml: fHtml
});
//Show
$('#BugEventTextNew' + ixBugEvent).slideDown(200, function() { // use slideDown instead of blind because of FF/Chrome graphical glitchs.
//Now that we've finished loading it, disable the 'loading' graphic and hide the edit icon.
var icons = $('#CaseEventEditIcon' + ixBugEvent).children();
$(icons[0]).show();
$(icons[1]).hide();
$('#CaseEventEditIcon' + ixBugEvent).hide();
});
//Activate buttons:
$('#TextSaveEditEvent' + ixBugEvent).click(function() { EditSave(ixBugEvent); return false; });
$('#TextCancelEditEvent' + ixBugEvent).click(function() { EditStop(ixBugEvent); return false; });
var sURLUploadFile = CaseEventEdit_sRawPageURL + Prefix('action=uploadFile');
new AjaxUpload('BugEventAttachButton' + ixBugEvent, {
hoverClass: 'CaseEventEditUploadHover',
action: sURLUploadFile,
name: CaseEventEdit_sPluginPrefix + 'sFile',
autoSubmit: true,
responseType: false,
onChange: function(sFile, extension) { return AddAttachment(ixBugEvent, sFile); },
onSubmit: function(file, extension) { },
onComplete: function(sFile, response) {
if ($(response).attr('fOK')) {
hashFileToAttach[hashAttach[ixBugEvent][sFile]] = ParseData(response);
}
else {
var sErr = $(response).attr("sMsg");
if (sErr === undefined) {
sErr = "The server failed to receive the file- Perhaps the attachment is too large?";
}
$('#BugEventTextError' + ixBugEvent).html("There was a problem uploading " + sFile + ":
" + sErr).effect('highlight', {}, 2000);
RemoveFile(hashAttach[ixBugEvent][sFile], ixBugEvent);
}
Uploader.UploadComplete();
$('#CaseEventEdit_FileLoading' + hashAttach[ixBugEvent][sFile]).fadeOut('slow', function() { $(this).remove(); });
}
});
};
var sURL = CaseEventEdit_sRawPageURL;
var ixEdit = hashBEToEdit[ixBugEvent];
if (ixEdit === undefined) {
ixEdit = -1;
}
sURL += Prefix('action=getEditS');
sURL += Prefix('ixBugEvent=' + encodeURIComponent(ixBugEvent));
sURL += Prefix('ixEdit=' + encodeURIComponent(ixEdit));
jQuery.get(sURL, fxn);
}
function EditSave(ixBugEvent) {
//If already saving, back off.
if (IsEditSaving(ixBugEvent)) {
return;
}
//Mark that we're working
SetEditSaving(ixBugEvent, true);
var textAreaNew = $('#BugEventTextArea' + ixBugEvent);
var textAreaNewFormat = $('#BugEventTextArea' + ixBugEvent + "_sFormat");
//If save is a failure, notice it.
var fxnFail = function(ixEditLatest, sErr, status) {
if (sErr == 'Nothing Changed') {
//Tried to save something which was the same as the current version.
//Although effectively a 'cancel', we want to do a force refresh so as to have consistent side-effects. (like, say, with history.)
hashForceRefresh[ixBugEvent] = true;
EditStop(ixBugEvent);
return;
}
if (sErr == 'Newer') {
//The case has been edited since we last viewed it.
//Show the diff between our current and the latest version,
Historian.ShowHistory(ixBugEvent, ixEditLatest, hashBEToEdit[ixBugEvent]);
//Display warning text explaining what's going on,
$('#BugEventTextError' + ixBugEvent).text("The changes above were submitted while you were editing. They will be overwritten unless you incorporate them into your own changes.").stop(true, true).effect('highlight', {}, 2000);
//Mark a force refresh (So that we get the latest bugevent if we cancel the edit.)
hashForceRefresh[ixBugEvent] = true;
//Take note not to bounce again
hashBEToEdit[ixBugEvent] = ixEditLatest;
//Continue editing
SetEditSaving(ixBugEvent, false);
return;
}
if (sErr == 'Deleted') {
hashForceRefresh[ixBugEvent] = true;
EditStop(ixBugEvent, function () {
$('#bugeventSummary_' + ixBugEvent).append('
Your edit could not be saved because the bug event was deleted
');
$('#bugevent_' + ixBugEvent).effect('highlight', {}, 2000);
});
}
if (!sErr) {
sErr = sREQUESTFAIL;
}
$('#BugEventTextError' + ixBugEvent).text("Unable to save edit: " + sErr);
};
//If save is successful, refresh the bugevent edited and add the new one.
var fxnOK = function(ixBugEventCreated) {
var fxn = function(sData, status) {
if ($(sData).attr('fOK') != 1) {
EditStop(ixBugEvent);
$('#bugeventBody_' + ixBugEvent).html('
Although the edit was saved successfully, Case Event Edit had a problem displaying the changes. The latest text will be available if you refresh this page. If this message appears with any frequency, please report the issue to FogBugz.
Error message:[' + $(sData).attr('sMsg') + ']
AjaxStatus:[' + status + ']');
return;
}
// Get rid of the rich textarea
DisableEditor(ixBugEvent)
//Rerender the updated bugevent.
//This will set hashBEToEdit[ixBugEvent] for us.
var j = $('#bugeventBody_' + ixBugEvent).parent('.bugevent').after($(sData).attr('sData0'));
updateHashBEToEdit();
j.remove();
$('#bugeventBody_' + ixBugEvent).effect('highlight', {}, 2000);
//Insert the new bugevent.
var sRenderLatest = $(sData).attr('sData1');
//Test for' fMostRecentEventFirst == 1' explicitally, since we don't know the 'false' value.
var insert = fMostRecentEventFirst == 1 ? $('#newBugEventInsertBelowPoint') : $('#newBugEventInsertAbovePoint');
//If insert has no children, create one. Else, add to the existing set.
if (insert.children().length == 0) {
insert.append(sRenderLatest);
}
else {
if (fMostRecentEventFirst == 1) {
insert.children(':first').before(sRenderLatest);
}
else {
insert.children(':last').after(sRenderLatest);
}
}
CaseEventEdit.FixImages();
//If we're still viewing the latest ixBugEvent (with no gaps), disable the warning scripts:
if ($(sData).attr('sData2') == 1) {
ixBugEventLatest = ixBugEventCreated;
$('input[name="ixBugEventLatest"]').val(ixBugEventLatest);
}
//If we were forcing a refresh... stop. We just did.
hashForceRefresh[ixBugEvent] = false;
};
var sURL = CaseEventEdit_sRawPageURL;
sURL += Prefix('action=minimalUpdates');
sURL += Prefix('ixBugEventThoughtLatest=' + encodeURIComponent(ixBugEventLatest));
sURL += Prefix('ixBugEventEdited=' + encodeURIComponent(ixBugEvent));
sURL += Prefix('ixBugEventCreated=' + encodeURIComponent(ixBugEventCreated));
jQuery.get(sURL, fxn);
};
//I'm a continuation!
var continuation = function() {
var sRgIxAttachment = '';
for (var sFile in hashAttach[ixBugEvent]) {
var ixAttachment = hashFileToAttach[hashAttach[ixBugEvent][sFile]];
if (ixAttachment !== undefined) {
if (sRgIxAttachment !== '') {
sRgIxAttachment += ',';
}
sRgIxAttachment += ixAttachment;
}
}
ajaxEditSave(textAreaNew.val(), textAreaNewFormat.val() || '', sRgIxAttachment, ixBugEvent, fxnOK, fxnFail);
};
//If there are files uploading, wait for them.
Uploader.OnNotUploading(continuation);
}
function ajaxEditSave(s, sFormat, sRgIxAttachment, ixBugEvent, fxnOK, fxnFail) {
var fxn = function(sAJAX, status) {
var fxnArg = function(s) { return $(sAJAX).attr(s); };
if (fxnArg('fOK') == 1) {
fxnOK(fxnArg('sData1'));
}
else {
fxnFail(fxnArg('sData0'), fxnArg('sMsg'), status);
}
};
var ixEditCurrent = hashBEToEdit[ixBugEvent];
if (ixEditCurrent === undefined) {
ixEditCurrent = -1;
}
var sData = Prefix('action=save');
sData += Prefix('s=' + encodeURIComponent(s));
sData += Prefix('sFormat=' + encodeURIComponent(sFormat));
sData += Prefix('sRgIxAttachment=' + encodeURI(sRgIxAttachment));
sData += Prefix('ixBugEvent=' + encodeURIComponent(ixBugEvent));
sData += Prefix('ixEditCurrent=' + encodeURIComponent(ixEditCurrent));
sData += Prefix('actionToken=' + CaseEventEdit_sActionToken);
$.ajax({ type: "POST",
url: CaseEventEdit_sRawPageURL,
success: fxn,
data: sData
});
}
function EditStop(ixBugEvent, fxnAfter) {
//Display the normal bugevent view:
if (hashForceRefresh[ixBugEvent]) {
//Re-render
hashForceRefresh[ixBugEvent] = false; //Only try once.
var fxn = function(sData, status) {
if ($(sData).attr('fOK') != 1) {
//If failure, don't bother with a rendering- just restore the old stuff.
//This acts like a 'cancel'... History will remain open, and the edit box will slide closed.
EditStop(ixBugEvent);
return;
}
// Get rid of the rich textarea
DisableEditor(ixBugEvent)
//The rendering will set hashBEToEdit[ixBugEvent] and hashAttach for us.
$('#bugeventBody_' + ixBugEvent).parent('.bugevent').after(ParseData(sData)).remove();
$('#bugeventBody_' + ixBugEvent).effect('highlight', {}, 2000);
CaseEventEdit.FixImages();
if (fxnAfter !== null) {
fxnAfter();
}
};
var sURL = CaseEventEdit_sRawPageURL;
sURL += Prefix('action=renderBugEvent');
sURL += Prefix('ixBugEvent=' + encodeURIComponent(ixBugEvent));
jQuery.get(sURL, fxn);
}
else {
//Remove the editing dialog:
DisableEditor(ixBugEvent);
$('#BugEventTextNew' + ixBugEvent).hide('blind', {}, 200, function() {
$(this).remove();
});
//Just make the old rendering visible again
var insertion = GetInsertionPoint(ixBugEvent);
insertion.attr('editing', 'false');
$('#CaseEventEditIcon' + ixBugEvent).show();
//Blank the attachments queue:
hashAttach[ixBugEvent] = undefined;
if (fxnAfter !== null) {
fxnAfter();
}
}
}
return members;
}
//Historian constructor
function ConstructHistorian() {
//Public Members:
var members = {
ToggleHistory: ToggleHistory,
ShowHistory: ShowOrRefreshHistory,
HideHistory: HideHistory,
RefreshHistoryFromSelectObj: RefreshHistoryFromSelectObj
};
//Private members:
function SetHistoryLoading(ixBugEvent, fLoading) {
var jLoading = $('#EventHistory' + ixBugEvent);
if (fLoading) {
jLoading.text('[Loading]');
}
else {
jLoading.html(jLoading.attr('value'));
}
}
function DLCLHistory(ixBugEvent) {
DropListControl.refreshWithin($('#CaseEventEditHistory' + ixBugEvent));
}
var FlashHistory = function(ixBugEvent) {
$('#CaseEventEditHistory' + ixBugEvent).stop(true, true).effect('highlight', {}, 2000);
};
function HideHistory(ixBugEvent) {
$("#CaseEventEditHistory" + ixBugEvent).stop(true).effect('blind', {}, 'fast', function() {
$(this).remove();
$("#EventHistory" + ixBugEvent).attr('fShowing', 0);
});
}
/****************************
* History Ajaxy functions: *
****************************/
function ShowOrRefreshHistory(ixBugEvent, ixEditNew, ixEditOld) {
if ($('#EventHistory' + ixBugEvent).attr('fShowing') == 1) {
//refresh
if (ixEditOld === undefined) {
ixEditOld = -1;
}
RefreshHistory(ixBugEvent, ixEditNew, ixEditOld);
}
else {
//show
ToggleHistory(ixBugEvent, ixEditNew, ixEditOld, true);
}
}
function CleanDataForIE(sData) {
//IE8 MEGAHACK, (because white-space:pre-wrap is not respected, and whitespace is collapsed upon DOM insertion):
//If not inside a <>, convert all spaces to 's.
if ($.browser.msie) {
var sOut = '';
var cLB = 0;
for (var ixData = 0, lenData = sData.length; ixData < lenData; ixData++) {
var ch = sData.charAt(ixData);
if (ch == '<') {
cLB++;
}
else if (ch == '>' && cLB > 0) {
cLB--;
}
else if (ch === ' ') {
if (cLB === 0) {
ch = " "
}
}
sOut += ch;
}
return sOut;
}
return sData;
}
function ToggleHistory(ixBugEvent, ixEditNew, ixEditOld, fFlash) {
//Until the history is fixed for Safari, give an error rather than puking.
if (window.safari) {
$('#EventHistory' + ixBugEvent).html('
[Unavailable in Safari]').stop(true, true).effect('highlight', {}, 5000);
return;
}
//If already exists, hide
if ($('#EventHistory' + ixBugEvent).attr('fShowing') == 1) {
HideHistory(ixBugEvent);
return;
}
$("#EventHistory" + ixBugEvent).attr('fShowing', 1);
//Mark us as loading:
SetHistoryLoading(ixBugEvent, true);
//Get diff:
var fxn = function(sAJAX, status) {
var sData;
if ($(sAJAX).attr('fOK') == 1) {
sData = ParseData(sAJAX);
}
else {
sData = $(sAJAX).attr('sMsg');
if (!sData) { sData = sREQUESTFAIL; }
}
//Create and show the history:
var sHistory = '
';
Editor.GetInsertionPoint(ixBugEvent).before(sHistory);
$('#CaseEventEditHistory' + ixBugEvent).html(CleanDataForIE(sData)).slideDown('fast'); // use slideDown instead of blind because of an IE8 graphical glitch.
DLCLHistory(ixBugEvent);
//Remove the 'loading' notification.
SetHistoryLoading(ixBugEvent, false);
if (fFlash) {
FlashHistory(ixBugEvent);
}
};
if (ixEditNew === undefined) {
ixEditNew = hashBEToEdit[ixBugEvent];
//if ixEditNew is still undefined at this point, ajaxGetDiff is going to fail.
//If a history view is visible, however, it should not be undefined unless we're in Bulk Edit mode.
if (CaseEventEdit_fBulkEdit && ixEditNew === undefined) {
ixEditNew = -1;
}
}
if (ixEditOld === undefined) {
ixEditOld = -1;
}
ajaxGetDiff(ixBugEvent, ixEditNew, ixEditOld, fxn);
}
function RefreshHistoryFromSelectObj(objSelect) {
//Yield momentarily so that the javascript from the dropdowns doesn't step on us.
//If it manages to anyway, the 'loading' text is obscured- no biggie.
setTimeout(function() {
var ixBugEvent, ixEditOld, ixEditNew;
//Extract the params from the Option:
//They look like this: "[ixBugEvent,ixEditOld,ixEditNew]"
var rgArgs = null;
$(objSelect).children().each(function() {
if ($(this).attr('selected')) {
var re = /\[[0-9]+,[0-9]+,[0-9]+\]/;
if (re.test($(this).val())) {
rgArgs = eval($(this).val()); //Using 'eval' as my JSON parser.
//loading notifier.
var rg = [$('#idDropList_selectNew' + rgArgs[0] + '_oText'), $('#idDropList_selectOld' + rgArgs[0] + '_oText')];
rg[0].val('Loading...');
rg[1].val('Loading...');
}
}
});
if (rgArgs === null) {
return;
}
ixBugEvent = rgArgs[0];
ixEditOld = rgArgs[1];
ixEditNew = rgArgs[2];
ajaxPerformRefresh(ixBugEvent, ixEditNew, ixEditOld, function() { });
}, 10);
}
function ajaxPerformRefresh(ixBugEvent, ixEditNew, ixEditOld, fxnFinally) {
//Get diff:
var fxn = function(sAJAX, status) {
var sData;
if ($(sAJAX).attr('fOK') == 1) {
sData = ParseData(sAJAX);
}
else {
sData = $(sAJAX).attr('sMsg');
if (!sData) { sData = sREQUESTFAIL; }
}
//Update the history:
$('#CaseEventEditHistory' + ixBugEvent).html(CleanDataForIE(sData));
DLCLHistory(ixBugEvent);
fxnFinally();
};
ajaxGetDiff(ixBugEvent, ixEditNew, ixEditOld, fxn);
}
function RefreshHistory(ixBugEvent, ixEditNew, ixEditOld) {
SetHistoryLoading(ixBugEvent, true);
var fxnFinally = function() {
SetHistoryLoading(ixBugEvent, false);
//Flash!
FlashHistory(ixBugEvent);
};
ajaxPerformRefresh(ixBugEvent, ixEditNew, ixEditOld, fxnFinally);
}
function ajaxGetDiff(ixBugEvent, ixEditNew, ixEditOld, fxn) {
var sURL = CaseEventEdit_sRawPageURL;
sURL += Prefix('action=diff');
sURL += Prefix('ixBugEvent=' + encodeURIComponent(ixBugEvent));
sURL += Prefix('ixEditNew=' + encodeURIComponent(ixEditNew));
sURL += Prefix('ixEditOld=' + encodeURIComponent(ixEditOld));
jQuery.get(sURL, fxn);
}
return members;
}
return members;
} ();
$(document).ready(function() {
var hideAttachments = function() {
$('.bugEvent[hide]').each(function() {
var parts = $(this).attr('hide').split('|');
if (parts.length == 2) {
var ixBugEvent = parts[0];
var sFilename = parts[1];
$("#containerAttachmentList_" + ixBugEvent + " .bugEvent:has(a[href*='sFileName=" + sFilename + "'])").hide();
}
else if (parts.length == 3) {
var ixBugEvent = parts[0];
var sFilename = parts[1];
var ixAttachment = parts[2];
$("#containerAttachmentList_" + ixBugEvent + " .attachment:has(a[href*='ixAttachment=" + ixAttachment + "'])").hide();
}
});
}
hideAttachments();
$('#bugEventHistory').bind("ajaxComplete", hideAttachments).bind("changeBug", hideAttachments);
});
var NotifyPlugin = new function() {
this.UserNames = function() {
if (typeof DB !== "object" || typeof DB.Person !== "object") {
return [];
}
var retval = $.map(
DB.Person.select(function(person) { return !(person.fDeleted || person.fCommunity); }),
function(person) { return person.sFullName; });
return retval;
};
this.UniqueCandidateName = function(s) {
var sUpper = s.toUpperCase();
// Return any exact matches
// (special case for one user having a name that is a substring of another user's name)
var rgsExact = $.grep(NotifyPlugin.UserNames(),
function(sName) { return sName.toUpperCase() === sUpper; });
if (rgsExact.length === 1) {
return rgsExact[0];
}
// If the substring uniquely identifies the user, return that
var rgsCandidate = $.grep(NotifyPlugin.UserNames(),
function(sName) { return sName.toUpperCase().indexOf(sUpper) > -1; });
if (rgsCandidate.length === 1) {
return rgsCandidate[0];
}
return "";
};
this.ValidUserName = function(s) {
return NotifyPlugin.UniqueCandidateName(s) !== "";
};
this.CanonicalUserName = function(s) {
var sUnique = NotifyPlugin.UniqueCandidateName(s);
return sUnique === "" ? s : sUnique;
};
} ();