Integration of validation results into the file/diff viewer by kmaglione (bug 663254)
This commit is contained in:
Родитель
90f1fcf912
Коммит
132d5fdc56
|
@ -1,24 +1,30 @@
|
|||
<div id="content-wrapper">
|
||||
<div>
|
||||
<div id="diff-wrapper">
|
||||
<div class="diff-bar js-hidden"></div>
|
||||
{% if viewer %}
|
||||
{% if viewer.selected %}
|
||||
{% if not viewer.selected['binary'] %}
|
||||
<pre id="content" class="brush: {{ viewer.selected['syntax'] }}; toolbar: false">{{ content }}</pre>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if diff %}
|
||||
{% if left or right %}
|
||||
<pre id="diff" class="diff-bar-height js-hidden brush: diff; toolbar: false"></pre>
|
||||
<pre class="left js-hidden">{{ left }}</pre>
|
||||
<pre class="right js-hidden">{{ right }}</pre>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if viewer %}
|
||||
{% if viewer.selected %}
|
||||
{% if not viewer.selected['binary'] %}
|
||||
<pre id="content" class="brush: {{ viewer.selected['syntax'] }}; toolbar: false">{{ content }}</pre>
|
||||
{% endif %}
|
||||
{% with selected = viewer.selected %}
|
||||
{% include "files/file.html" %}
|
||||
{% endwith %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if diff %}
|
||||
<div id="diff-wrapper">
|
||||
{% if left or right %}
|
||||
<div class="diff-bar js-hidden"></div>
|
||||
<pre id="diff" class="diff-bar-height js-hidden brush: diff; toolbar: false"></pre>
|
||||
<pre class="left js-hidden">{{ left }}</pre>
|
||||
<pre class="right js-hidden">{{ right }}</pre>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if diff.left and diff.left.selected %}
|
||||
{% with selected = diff.left.selected %}
|
||||
{% include "files/file.html" %}
|
||||
|
|
|
@ -3,5 +3,5 @@
|
|||
{% if value['filename'] != value['truncated'] %}title="{{ value['filename'] }}"{% endif %}
|
||||
data-delay="0"
|
||||
href="{{ value['url'] }}"
|
||||
data-short="{{ value['short'] }}">{{ value['truncated'] }}</a>
|
||||
data-short="{{ value['short'] }}"><span>{{ value['truncated'] }}</span></a>
|
||||
</li>
|
||||
|
|
|
@ -11,7 +11,9 @@
|
|||
<div id="metadata" class="js-hidden"
|
||||
data-name="{{ addon.name }}"
|
||||
data-slug="{{ addon.slug }}"
|
||||
data-version="{{ version }}"></div>
|
||||
data-version="{{ version }}"
|
||||
data-validate-url="{{ validate_url }}"
|
||||
data-validation-failed="{{ _("Validation failed:") }}"></div>
|
||||
|
||||
<h3>
|
||||
<a href="{{ file_link['url'] }}">{{ addon.name }} {{ version }}</a>
|
||||
|
@ -29,6 +31,9 @@
|
|||
</p>
|
||||
<div class="notification-box error js-hidden"></div>
|
||||
{% endif %}
|
||||
<div id="validating" class="js-hidden">
|
||||
<span class="waiting">{{ _('Fetching validation results...') }}</span>
|
||||
</div>
|
||||
<div id="files">
|
||||
{% if files %}
|
||||
<h4>{{ _('Files:') }}</h4>
|
||||
|
@ -46,10 +51,10 @@
|
|||
<table id="commands">
|
||||
<tr><th><code>k</code></th> <td><a href="#" id="files-up">{{ _('Previous file') }}</a></td></tr>
|
||||
<tr><th><code>j</code></th> <td><a href="#" id="files-down">{{ _('Next file') }}</a></td></tr>
|
||||
{% if diff %}
|
||||
<tr><th><code>[c</code></th> <td><a href="#" id="files-change-prev">{{ _('Previous change') }}</a></td></tr>
|
||||
<tr><th><code>]c</code></th> <td><a href="#" id="files-change-next">{{ _('Next change') }}</a></td></tr>
|
||||
{% endif %}
|
||||
{% if diff %}
|
||||
<tr><th><code>[c</code></th> <td><a href="#" id="files-change-prev">{{ _('Previous change') }}</a></td></tr>
|
||||
<tr><th><code>]c</code></th> <td><a href="#" id="files-change-next">{{ _('Next change') }}</a></td></tr>
|
||||
{% endif %}
|
||||
<tr><th><code>e</code></th> <td><a href="#" id="files-expand-all">{{ _('Expand all') }}</a></td></tr>
|
||||
<tr><th><code>h</code></th> <td><a href="#" id="files-hide">{{ _('Hide or unhide tree') }}</a></td></tr>
|
||||
<tr><th><code>w</code></th> <td><a href="#" id="files-wrap">{{ _('Wrap or unwrap text') }}</a></td></tr>
|
||||
|
|
|
@ -26,7 +26,16 @@ def setup_viewer(request, file_obj):
|
|||
'version': file_obj.version,
|
||||
'addon': file_obj.version.addon,
|
||||
'status': False,
|
||||
'selected': {}}
|
||||
'selected': {},
|
||||
'validate_url': ''}
|
||||
|
||||
|
||||
if (acl.action_allowed(request, 'Editors', '%') or
|
||||
acl.check_addon_ownership(request, file_obj.version.addon,
|
||||
viewer=True, ignore_disabled=True)):
|
||||
data['validate_url'] = reverse('devhub.json_file_validation',
|
||||
args=[file_obj.version.addon.slug,
|
||||
file_obj.id])
|
||||
|
||||
if acl.action_allowed(request, 'Editors', '%'):
|
||||
data['file_link'] = {'text': _('Back to review'),
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
#files li a {
|
||||
display: inline-block;
|
||||
padding: 2px 20px;
|
||||
padding: 1px 1px 2px 20px;
|
||||
}
|
||||
|
||||
#files ul.root {
|
||||
|
@ -45,6 +45,11 @@ body.file-viewer div.section {
|
|||
padding-left: 0;
|
||||
}
|
||||
|
||||
#validating {
|
||||
text-align: center;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
span.number {
|
||||
width: 4em;
|
||||
display: inline-block;
|
||||
|
@ -84,18 +89,75 @@ a.open {
|
|||
background: url('../../img/icons/minus.gif') 0 no-repeat;
|
||||
}
|
||||
|
||||
a.diff {
|
||||
#files a > span {
|
||||
-moz-boder-radius: 4px;
|
||||
border-radius: 4px;
|
||||
padding: 3px;
|
||||
}
|
||||
|
||||
a.diff > span {
|
||||
background-color: #ffffcc;
|
||||
}
|
||||
|
||||
a.known > span {
|
||||
color: #bbb;
|
||||
}
|
||||
|
||||
#files a.notice > span, #files a.warning > span, #files a.error > span {
|
||||
margin: -1px;
|
||||
}
|
||||
|
||||
#files a.notice > span {
|
||||
border: 1px dotted blue;
|
||||
}
|
||||
|
||||
#files a.warning.warning > span {
|
||||
border: 1px dotted red;
|
||||
}
|
||||
|
||||
#files a.error.error.error > span {
|
||||
border: 1px solid red;
|
||||
}
|
||||
|
||||
a.selected > span {
|
||||
background-color: #ddf8dd;
|
||||
}
|
||||
|
||||
.gutter a.notice, .gutter a.warning, .gutter a.error {
|
||||
margin: -1px;
|
||||
-moz-border-radius: 3px;
|
||||
border-radius: 3px;
|
||||
border: 1px solid black;
|
||||
}
|
||||
.code .notice, .code .warning, .code .error {
|
||||
margin: -1px;
|
||||
}
|
||||
|
||||
.gutter a.notice, .diff-bar .notice.notice {
|
||||
background-color: yellow;
|
||||
}
|
||||
.code .notice {
|
||||
border: 1px dotted yellow;
|
||||
}
|
||||
|
||||
.gutter a.warning.warning, .diff-bar .warning.warning.warning {
|
||||
background-color: orange;
|
||||
}
|
||||
.code .warning.warning {
|
||||
border: 1px dotted orange;
|
||||
}
|
||||
|
||||
.gutter a.error.error.error, .diff-bar .error.error.error.error {
|
||||
background-color: red;
|
||||
}
|
||||
.code .error.error.error {
|
||||
border: 1px dotted red;
|
||||
}
|
||||
|
||||
div.diff-bar {
|
||||
margin-left: -1px;
|
||||
}
|
||||
|
||||
a.selected {
|
||||
background-color: #ddf8dd;
|
||||
}
|
||||
|
||||
.waiting {
|
||||
background-image: url(../../img/zamboni/loading-white.gif);
|
||||
background-repeat: no-repeat;
|
||||
|
@ -123,7 +185,7 @@ a.selected {
|
|||
padding: 0 0 0 1ex;
|
||||
}
|
||||
|
||||
#diff {
|
||||
#diff, #content {
|
||||
padding-left: 11px;
|
||||
}
|
||||
|
||||
|
@ -140,7 +202,6 @@ td.gutter, td.code {
|
|||
border: 1px solid gray;
|
||||
width: 10px;
|
||||
position: absolute;
|
||||
overflow: hidden;
|
||||
height: 200px;
|
||||
}
|
||||
|
||||
|
@ -174,6 +235,89 @@ td.gutter, td.code {
|
|||
max-width: 100%;
|
||||
}
|
||||
|
||||
#tooltip > span {
|
||||
white-space: pre-wrap;
|
||||
text-align: left;
|
||||
max-width: 70ex;
|
||||
}
|
||||
|
||||
|
||||
.message {
|
||||
display:none;
|
||||
|
||||
position: absolute;
|
||||
padding-left: 10px;
|
||||
top: -.2em;
|
||||
left: 100%;
|
||||
|
||||
position: absolute;
|
||||
z-index: 16385;
|
||||
text-align: left;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.diff-bar .message {
|
||||
top: -.8em;
|
||||
margin-top: -4px;
|
||||
}
|
||||
|
||||
.message-inner {
|
||||
position: relative;
|
||||
padding: 0.5em 1em;
|
||||
|
||||
border: 1px solid #fff;
|
||||
border-radius: .8em;
|
||||
background: #2A4364;
|
||||
color: white;
|
||||
border-radius: .8em;
|
||||
-moz-border-radius: .8em;
|
||||
-webkit-border-radius: .8em;
|
||||
}
|
||||
|
||||
.message a {
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
text-decoration: underline !important;
|
||||
}
|
||||
|
||||
.message-inner > div {
|
||||
line-height: 1.2em;
|
||||
width: 70ex;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
.message-inner > div + div {
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
.message p {
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
.message-inner::before {
|
||||
content: "\00a0";
|
||||
display: block; /* reduce the damage in FF3.0 */
|
||||
position: absolute;
|
||||
width: 0;
|
||||
height: 0;
|
||||
margin-top: -6px;
|
||||
top: 1.1em;
|
||||
left: -16px;
|
||||
border: solid transparent;
|
||||
border-width: 6px 9px;
|
||||
border-right-color: #2A4364;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.message-container {
|
||||
position: relative;
|
||||
overflow: visible !important;
|
||||
}
|
||||
|
||||
.message-container:hover > .message {
|
||||
display: block;
|
||||
}
|
||||
|
||||
|
||||
.number-combo {
|
||||
display: inline-block;
|
||||
}
|
||||
|
|
|
@ -942,7 +942,7 @@ div.popup-shim {
|
|||
line-height: 1.2em;
|
||||
}
|
||||
|
||||
#tooltip:before {
|
||||
#tooltip::before {
|
||||
content: "\00a0";
|
||||
display: block; /* reduce the damage in FF3.0 */
|
||||
position: absolute;
|
||||
|
@ -956,7 +956,7 @@ div.popup-shim {
|
|||
border-top-color: #2A4364;
|
||||
pointer-events: none;
|
||||
}
|
||||
#tooltip.error:before {
|
||||
#tooltip.error::before {
|
||||
border-top-color: #6c1a1a;
|
||||
}
|
||||
|
||||
|
|
|
@ -72,7 +72,7 @@ if (typeof SyntaxHighlighter !== 'undefined') {
|
|||
return html;
|
||||
};
|
||||
|
||||
SyntaxHighlighter.Highlighter.prototype.getLineHtml = function(lineIndex, lineNumber, code) {
|
||||
SyntaxHighlighter.Highlighter.prototype.getLineHtml = function(lineIndex, lineNumber, code) {
|
||||
var classes = [
|
||||
'original',
|
||||
'line',
|
||||
|
@ -91,8 +91,11 @@ if (typeof SyntaxHighlighter !== 'undefined') {
|
|||
|
||||
/* HTML parsing with regex warning disclaimer. This lib writes out
|
||||
* well formed lines with <code> and <a>. We want a hint
|
||||
* of the line length without all the syntax highlighting in it. */
|
||||
var raw = code.replace(/<.*?>/g, '').replace(/&.*?;/g, ' ');
|
||||
* of the line length without all the syntax highlighting in it.
|
||||
* We also need to expand tab characters to the long end of
|
||||
* likely values to make sure long tab-indented lines are
|
||||
* processed. */
|
||||
var raw = code.replace(/<.*?>/g, '').replace(/&.*?;/g, ' ').replace(/\t/g, ' ');
|
||||
if (raw.length > 80) {
|
||||
classes.push('longline');
|
||||
}
|
||||
|
@ -123,13 +126,11 @@ jQuery.fn.numberInput = function(increment) {
|
|||
|
||||
var height = $self.outerHeight() / 2;
|
||||
|
||||
var $dom = $('<span>').attr({ 'class': 'number-combo' })
|
||||
.append($('<a>').attr({ 'class': 'number-combo-button-down',
|
||||
'href': '#' })
|
||||
.text('↓'))
|
||||
.append($('<a>').attr({ 'class': 'number-combo-button-up',
|
||||
'href': '#' })
|
||||
.text('↑'));
|
||||
var $dom = $('<span>', { 'class': 'number-combo' })
|
||||
.append($('<a>', { 'class': 'number-combo-button-down',
|
||||
'href': '#', 'text': '↓' }))
|
||||
.append($('<a>', { 'class': 'number-combo-button-up',
|
||||
'href': '#', 'text': '↑' }));
|
||||
|
||||
var $up = $dom.find('.number-combo-button-up').click(_pd(function(event, count) {
|
||||
count = count || (event.ctrlKey ? increment : 1) || 1;
|
||||
|
@ -165,6 +166,22 @@ jQuery.fn.numberInput = function(increment) {
|
|||
return this;
|
||||
};
|
||||
|
||||
jQuery.fn.appendMessage = function(message) {
|
||||
$(this).each(function() {
|
||||
var $self = $(this),
|
||||
$container = $self.find('.message-inner');
|
||||
|
||||
if (!$container.length) {
|
||||
$container = $('<div>', { 'class': 'message-inner' });
|
||||
$self.append($('<div>', { 'class': 'message' }).append($container))
|
||||
.addClass('message-container');
|
||||
}
|
||||
|
||||
$container.append($('<div>')[typeof message == "string" ? 'text' : 'html'](message));
|
||||
});
|
||||
return this;
|
||||
};
|
||||
|
||||
function bind_viewer(nodes) {
|
||||
$.each(nodes, function(x) {
|
||||
nodes['$'+x] = $(nodes[x]);
|
||||
|
@ -197,16 +214,19 @@ function bind_viewer(nodes) {
|
|||
/* We need to re-size the line numbers correctly depending upon
|
||||
the wrapping. */
|
||||
|
||||
var self = this;
|
||||
$node.each(function(){
|
||||
$node.each(function() {
|
||||
var $self = $(this),
|
||||
long_lines = $(this).find('td.code div.longline');
|
||||
long_lines = $(this).find('td.code div.longline'),
|
||||
changes = [];
|
||||
/* Use the longline hint to guess at long lines and
|
||||
* see what needs resizing. */
|
||||
$.each(long_lines, function() {
|
||||
var $this = $(this),
|
||||
k = parseInt($this.attr('class').match(/index(\d+)/)[1], 10);
|
||||
$self.find('td.gutter div.index' + k).css('height', $this.height() + 'px');
|
||||
changes.push(['td.gutter div.index' + k + ':eq(0)', $this.height() + 'px']);
|
||||
});
|
||||
$.each(changes, function(i, change) {
|
||||
$self.find(change[0]).css('height', change[1]);
|
||||
});
|
||||
});
|
||||
this.updateViewport(true);
|
||||
|
@ -235,13 +255,64 @@ function bind_viewer(nodes) {
|
|||
// Note SyntaxHighlighter has nuked the node and replaced it.
|
||||
$diff = node.find('#diff');
|
||||
this.size_line_numbers($diff, true);
|
||||
}
|
||||
|
||||
this.compute_messages(node);
|
||||
|
||||
if (window.location.hash && window.location.hash != 'top') {
|
||||
window.location = window.location;
|
||||
}
|
||||
};
|
||||
this.message_type_map = {
|
||||
'error': 'error',
|
||||
'warning': 'warning',
|
||||
'notice': 'info'
|
||||
};
|
||||
this.compute_messages = function(node) {
|
||||
var $diff = node.find('#diff'),
|
||||
path = this.nodes.$files.find('a.file.selected').attr('data-short');
|
||||
|
||||
if (this.messages && this.messages.hasOwnProperty(path)) {
|
||||
var messages = this.messages[path];
|
||||
for (var i = 0; i < messages.length; i++) {
|
||||
var message = messages[i],
|
||||
$line = $('#L' + message.line),
|
||||
title = $line.attr('title'),
|
||||
$dom = $('<div>').append($('<strong>').html(format('{0}{1}: {2}',
|
||||
message.type[0].toUpperCase(),
|
||||
message.type.substr(1),
|
||||
message.message)));
|
||||
|
||||
$.each([].concat(message.description), function(i, msg) {
|
||||
$dom.append($('<p>').html(String(message.description)));
|
||||
});
|
||||
|
||||
if (message.line != null && $line.length) {
|
||||
$line.addClass(message.type)
|
||||
.parent()
|
||||
.appendMessage($dom);
|
||||
|
||||
$('.code .' + $line.parent().attr('class').match(/number\d+/)[0] + ':eq(0)')
|
||||
.addClass(message.type);
|
||||
} else {
|
||||
$('#diff-wrapper').before(
|
||||
$('<div>', { 'class': 'notification-box' })
|
||||
.addClass(this.message_type_map[message.type])
|
||||
.append($dom));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($diff.length || messages) {
|
||||
/* Build out the diff bar based on the line numbers. */
|
||||
var $sb = $diff.siblings('.diff-bar').eq(0),
|
||||
$gutter = $diff.find('td.gutter'),
|
||||
$lines = $gutter.find('div.line a');
|
||||
var $sb = $('.diff-bar'),
|
||||
$gutter = $('td.gutter'),
|
||||
$lines = $gutter.find('div.line > a');
|
||||
|
||||
$sb.empty();
|
||||
|
||||
if ($lines.length) {
|
||||
var changes = [];
|
||||
var flush = function($line, bottom) {
|
||||
var height = (bottom - $start.offset().top) * 100 / $gutter.height(),
|
||||
style = { 'height': height + "%" };
|
||||
|
@ -255,15 +326,14 @@ function bind_viewer(nodes) {
|
|||
style['margin-bottom'] = '-1px';
|
||||
}
|
||||
|
||||
$sb.append($('<a>', { 'href': $start.attr('href'), 'class': $start.attr('class'),
|
||||
'css': style }));
|
||||
changes.push([$start, style]);
|
||||
|
||||
$prev = $start;
|
||||
$start = $line;
|
||||
};
|
||||
|
||||
var $prev, $start = null;
|
||||
$lines.each(function () {
|
||||
$lines.each(function() {
|
||||
var $line = $(this);
|
||||
if (!$start) {
|
||||
$start = $line;
|
||||
|
@ -273,6 +343,17 @@ function bind_viewer(nodes) {
|
|||
});
|
||||
flush(null, $gutter.offset().top + $gutter.height());
|
||||
|
||||
$.each(changes, function(i, change) {
|
||||
var $start = change[0], style = change[1];
|
||||
|
||||
var $link = $('<a>', { 'href': $start.attr('href'), 'class': $start.attr('class'),
|
||||
'css': style }).appendTo($sb);
|
||||
|
||||
if ($start.is('.error, .notice, .warning')) {
|
||||
$link.appendMessage($start.parent().find('.message-inner > div').clone());
|
||||
}
|
||||
});
|
||||
|
||||
this.$diffbar = $sb;
|
||||
this.$viewport = $('<div>', { 'class': 'diff-bar-viewport' });
|
||||
this.$gutter = $gutter;
|
||||
|
@ -284,9 +365,85 @@ function bind_viewer(nodes) {
|
|||
this.updateViewport(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
this.update_validation = function(data) {
|
||||
var viewer = this;
|
||||
|
||||
if (window.location.hash && window.location.hash != 'top') {
|
||||
window.location = window.location;
|
||||
$('#validating').hide();
|
||||
if (data.validation) {
|
||||
this.validation = data.validation;
|
||||
|
||||
this.messages = {};
|
||||
var messages = data.validation.messages;
|
||||
for (var i = 0; i < messages.length; i++) {
|
||||
var path = [].concat(messages[i].file).join("/");
|
||||
|
||||
if (!this.messages[path]) {
|
||||
this.messages[path] = [];
|
||||
}
|
||||
this.messages[path].push(messages[i]);
|
||||
}
|
||||
|
||||
this.known_files = {};
|
||||
var metadata = data.validation.metadata;
|
||||
if (metadata && metadata.jetpack_identified_files) {
|
||||
var files = metadata.jetpack_identified_files;
|
||||
for (var file in files) {
|
||||
this.known_files[file] = ['JetPack'].concat(files[file]);
|
||||
}
|
||||
}
|
||||
|
||||
this.nodes.$files.find('.file').each(function() {
|
||||
var $self = $(this);
|
||||
|
||||
var known = viewer.known_files[$self.attr('data-short')];
|
||||
if (known) {
|
||||
$self.attr('title',
|
||||
format('Identified:\n' +
|
||||
' Library: {0} {2}\n' +
|
||||
' Original path: {1}',
|
||||
known))
|
||||
.addClass('known')
|
||||
.addClass('tooltip');
|
||||
}
|
||||
|
||||
var messages = viewer.messages[$self.attr('data-short')];
|
||||
if (messages) {
|
||||
var types = {};
|
||||
for (var i = 0; i < messages.length; i++) {
|
||||
types[messages[i].type] = true;
|
||||
}
|
||||
for (var type in types) {
|
||||
$self.addClass(type);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.nodes.$files.find('.directory').each(function() {
|
||||
var $self = $(this);
|
||||
var $ul = $self.parent().next();
|
||||
|
||||
$.each(['warning', 'error', 'notice'], function(i, type) {
|
||||
if ($ul.find('.' + type + ':eq(0)').length) {
|
||||
$self.addClass(type);
|
||||
}
|
||||
});
|
||||
if (!$ul.find('.file:not(.known):eq(0)').length) {
|
||||
$self.addClass('known');
|
||||
}
|
||||
});
|
||||
|
||||
this.compute_messages($('#content-wrapper'));
|
||||
}
|
||||
|
||||
var error = data.error || typeof data == "string" && data ||
|
||||
data && typeof data != "object";
|
||||
if (error) {
|
||||
$('#validating').after(
|
||||
$('<div>', { 'class': 'notification-box error',
|
||||
'text': format('{1} {2}',
|
||||
$("#metadata").attr('data-validation-failed'),
|
||||
error) }));
|
||||
}
|
||||
};
|
||||
this.updateViewport = function(resize) {
|
||||
|
@ -301,18 +458,15 @@ function bind_viewer(nodes) {
|
|||
var gutter = $gutter[0].getBoundingClientRect(),
|
||||
gutter_height = gutter.bottom - gutter.top,
|
||||
window_height = $(window).height(),
|
||||
diffbar_top = -Math.min(0, gutter.top) * 100 / gutter_height + "%";
|
||||
diffbar_top = -Math.min(0, gutter.top) * 100 / gutter_height + "%",
|
||||
height = Math.max(0, gutter_height + Math.min(0, gutter.top) - Math.max(gutter.bottom - window_height, 0));
|
||||
|
||||
if (resize) {
|
||||
var height = gutter_height + Math.min(0, gutter.top) - Math.max(gutter.bottom - window_height, 0);
|
||||
|
||||
$viewport.css({ 'height': height * 100 / gutter_height + "%", 'top': diffbar_top });
|
||||
|
||||
$diffbar.css({ 'height': Math.min($("#diff-wrapper").height(), window_height) + "px" });
|
||||
} else {
|
||||
$viewport.css({ 'top': diffbar_top });
|
||||
$diffbar.css({ 'height': Math.min($('#diff-wrapper').height(), window_height) + "px" });
|
||||
}
|
||||
|
||||
$viewport.css({ 'height': height * 100 / gutter_height + '%', 'top': diffbar_top });
|
||||
|
||||
if (gutter.bottom <= window_height) {
|
||||
$diffbar.css({ 'position': 'absolute', 'top': '', 'bottom': '0' });
|
||||
} else if (gutter.top > 0) {
|
||||
|
@ -398,11 +552,13 @@ function bind_viewer(nodes) {
|
|||
});
|
||||
return k;
|
||||
};
|
||||
this.toggle_wrap = function(state) {
|
||||
this.toggle_wrap = function(state, quick) {
|
||||
/* Toggles the content wrap in the page, starts off wrapped */
|
||||
this.wrapped = (state == 'wrap' || !this.wrapped);
|
||||
$('code').toggleClass('unwrapped');
|
||||
this.size_line_numbers($('#content-wrapper'), false);
|
||||
if (!quick) {
|
||||
this.size_line_numbers($('#content-wrapper'), false);
|
||||
}
|
||||
};
|
||||
this.toggle_files = function(state) {
|
||||
this.hidden = (state == 'hide' || !this.hidden);
|
||||
|
@ -421,13 +577,14 @@ function bind_viewer(nodes) {
|
|||
this.next_changed = function(offset) {
|
||||
var $files = this.nodes.$files.find('a.file'),
|
||||
selected = $files[this.get_selected()],
|
||||
isDiff = $('#diff').length;
|
||||
isDiff = $('#diff').length,
|
||||
filter = (isDiff ? '.diff' : '') + ':not(.known)';
|
||||
|
||||
var a = [], list = a;
|
||||
$files.each(function () {
|
||||
$files.each(function() {
|
||||
if (this == selected) {
|
||||
list = [selected];
|
||||
} else if (config.needreview_pattern.test($(this).attr('data-short')) && (!isDiff || $(this).hasClass('diff'))) {
|
||||
} else if (config.needreview_pattern.test($(this).attr('data-short')) && $(this).is(filter)) {
|
||||
list.push(this);
|
||||
}
|
||||
});
|
||||
|
@ -439,7 +596,9 @@ function bind_viewer(nodes) {
|
|||
}
|
||||
};
|
||||
this.next_delta = function(forward) {
|
||||
var $deltas = $('td.code .line.add, td.code .line.delete'),
|
||||
var classes = $("#diff").length ? 'add delete' : 'warning notice error',
|
||||
$deltas = $(classes.split(/ /g)
|
||||
.map(function(className) { return 'td.code .line.' + className; }).join(', ')),
|
||||
$lines = $('td.code .line');
|
||||
$lines.indexOf = Array.prototype.indexOf;
|
||||
|
||||
|
@ -488,10 +647,8 @@ function bind_viewer(nodes) {
|
|||
viewer.toggle_leaf($(this));
|
||||
}));
|
||||
|
||||
if ($('#diff').length) {
|
||||
$(window).resize(debounce(function () { viewer.updateViewport(true); }));
|
||||
$(window).scroll(debounce(function () { viewer.updateViewport(false); }));
|
||||
}
|
||||
$(window).resize(debounce(function() { viewer.updateViewport(true); }));
|
||||
$(window).scroll(debounce(function() { viewer.updateViewport(false); }));
|
||||
|
||||
$('#files-up').click(_pd(function() {
|
||||
viewer.next_changed(-1);
|
||||
|
@ -523,16 +680,34 @@ function bind_viewer(nodes) {
|
|||
});
|
||||
}));
|
||||
|
||||
if ($('#metadata').attr('data-validate-url')) {
|
||||
$('#validating').css('display', 'block');
|
||||
|
||||
$.ajax({type: 'POST',
|
||||
url: $('#metadata').attr('data-validate-url'),
|
||||
data: {},
|
||||
success: function(data) {
|
||||
viewer.update_validation(data);
|
||||
},
|
||||
error: function(XMLHttpRequest, textStatus, errorThrown) {
|
||||
viewer.update_validation(textStatus);
|
||||
},
|
||||
dataType: 'json'
|
||||
});
|
||||
}
|
||||
|
||||
viewer.nodes.$files.find('.file').click(_pd(function() {
|
||||
viewer.select($(this));
|
||||
viewer.toggle_wrap('wrap');
|
||||
viewer.toggle_wrap('wrap', true);
|
||||
}));
|
||||
|
||||
$(window).bind('popstate', function() {
|
||||
if (viewer.last != location.pathname) {
|
||||
viewer.nodes.$files.find('.file').each(function() {
|
||||
if ($(this).attr('href') == location.pathname) {
|
||||
viewer.select($(this));
|
||||
if (!$(this).is('.selected')) {
|
||||
viewer.select($(this));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -540,7 +715,7 @@ function bind_viewer(nodes) {
|
|||
|
||||
var prefixes = {},
|
||||
keys = {};
|
||||
$('#commands code').each(function () {
|
||||
$('#commands code').each(function() {
|
||||
var $code = $(this),
|
||||
$link = $code.parents('tr').find('a'),
|
||||
key = $code.text();
|
||||
|
@ -553,7 +728,9 @@ function bind_viewer(nodes) {
|
|||
|
||||
var buffer = '';
|
||||
$(document).bind('keypress', function(e) {
|
||||
if (e.charCode && !(e.altKey || e.ctrlKey || e.metaKey)) {
|
||||
if (e.charCode && !(e.altKey || e.ctrlKey || e.metaKey) &&
|
||||
![HTMLInputElement, HTMLSelectElement, HTMLTextAreaElement]
|
||||
.some(function (iface) { return e.target instanceof iface })) {
|
||||
buffer += String.fromCharCode(e.charCode);
|
||||
if (keys.hasOwnProperty(buffer)) {
|
||||
e.preventDefault();
|
||||
|
@ -581,19 +758,20 @@ function bind_viewer(nodes) {
|
|||
var $tabstops = $('#tab-stops')
|
||||
.numberInput(4)
|
||||
.val(Number(storage.get(localTabstopsKey) || storage.get(tabstopsKey)) || 4)
|
||||
.change(function() {
|
||||
.change(function(event, global) {
|
||||
rule.style.tabSize = rule.style.MozTabSize = $(this).val();
|
||||
storage.set(localTabstopsKey, $(this).val());
|
||||
if (!global)
|
||||
storage.set(localTabstopsKey, $(this).val());
|
||||
storage.set(tabstopsKey, $(this).val());
|
||||
})
|
||||
.change();
|
||||
.trigger('change', true);
|
||||
}
|
||||
|
||||
return viewer;
|
||||
}
|
||||
|
||||
var viewer = null;
|
||||
$(document).ready(function() {
|
||||
var viewer = null;
|
||||
var nodes = { files: '#files', thinking: '#thinking', commands: '#commands' };
|
||||
function poll_file_extraction() {
|
||||
$.getJSON($('#extracting').attr('data-url'), function(json) {
|
||||
|
|
|
@ -44,21 +44,21 @@ jQuery.fn.tooltip = function(tip_el) {
|
|||
timeout = false,
|
||||
$tgt, $title, delay;
|
||||
|
||||
|
||||
function setTip() {
|
||||
if (!$tgt) return;
|
||||
var pos = $tgt.offset(),
|
||||
title = $title.attr('title');
|
||||
title = $title.attr('title'),
|
||||
html = $title.attr('data-tooltip-html');
|
||||
|
||||
delay = $title.is('[data-delay]') ? $title.attr('data-delay') : 300;
|
||||
|
||||
if(title.indexOf('::') > 0) {
|
||||
if(!html && title.indexOf('::') > 0) {
|
||||
var title_split = title.split('::');
|
||||
$msg.text("");
|
||||
$msg.append($("<strong>", {'text': title_split[0].trim()}));
|
||||
$msg.append($("<span>", {'text': title_split[1].trim()}));
|
||||
} else {
|
||||
$msg.text(title);
|
||||
$msg[html ? 'html' : 'text'](title);
|
||||
}
|
||||
|
||||
$title.attr('data-oldtitle', title).attr('title', '');
|
||||
|
|
Загрузка…
Ссылка в новой задаче