in static/js/zamboni/validator.js [246:346]
MsgVisitor.prototype.message = function (msg, options) {
if (!this.filterMessage(msg)) {
return;
}
if (typeof this.msgSet[msg.uid] !== 'undefined') {
return;
}
this.msgSet[msg.uid] = true;
let tier = this.getTier(msg.tier, options),
msgDiv = $('<div class="msg"><h5></h5></div>'),
effectiveType = this.getMsgType(msg),
prefix = effectiveType == 'error' ? gettext('Error') : gettext('Warning');
tier.tallyMsgType(effectiveType);
msgDiv.attr('id', 'v-msg-' + msg.uid);
msgDiv.addClass('msg-' + effectiveType);
// The "message" and "description" properties are escaped and linkified
// before we receive them.
$('h5', msgDiv).html(msg.message); // Sanitized HTML value.
// The validator returns the "description" as either string, or
// arrays of strings. We turn it into arrays when sanitizing.
$.each(msg.description, function (i, val) {
let $desc = $('<p>').html(val); // Sanitized HTML value.
if (i === 0) {
$desc.prepend(format('<strong>{0}:</strong> ', prefix));
}
msgDiv.append($desc);
});
if (msg.file) {
let file = msg.file;
if (typeof file !== 'string') {
// For sub-packages, this will be a list of archive paths and
// a final file path, which we need to turn into a string.
// ['foo.xpi', 'chrome/thing.jar', 'content/file.js']
file = file.join('/');
}
let $link;
if (this.fileURL && this.fileID) {
let url = this.fileURL + '?path=' + file;
if (msg.line) {
url += '#L' + msg.line;
}
$link = $('<a>', {
href: url,
text: file,
target: 'file-viewer-' + this.fileID,
});
} else {
// There's no file browse URL for bare file uploads, so
// just display a path without a link to the sources.
$link = $('<span>', { text: file });
}
let $context = $('<div class="context">').append(
$('<div class="file">').append($link),
);
if (msg.context) {
let $code = $('<div class="code"></div>');
let $lines = $('<div class="lines"></div>');
let $innerCode = $('<div class="inner-code"></div>');
$code.append($lines, $innerCode);
// The line number in the message refers to the middle
// line of the context, so adjust accordingly.
let offset = Math.floor(msg.context.length / 2);
msg.context = formatCodeIndentation(msg.context);
$.each(msg.context, function (idx, code) {
if (code != null) {
$lines.append($('<div>', { text: msg.line + idx - offset }));
$innerCode.append($('<div>', { text: code }));
}
});
$context.append($code);
} else if (msg.line && typeof msg.column !== 'undefined') {
// Normally, the line number would be displayed with the
// context. If we have no context, display it with the
// filename.
$link.text(
format(gettext('{0} line {1} column {2}'), [
file,
msg.line,
msg.column,
]),
);
} else if (msg.line) {
$link.text(format(gettext('{0} line {1}'), [file, msg.line]));
}
msgDiv.append($context);
}
$('.tier-results', tier.$dom).append(msgDiv);
};