")
.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 Fog Creek Software.
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;
};
} ();