Родитель
338a431052
Коммит
10a3768422
|
@ -8,8 +8,9 @@ from django.conf import settings
|
|||
from django.utils.datastructures import SortedDict
|
||||
from django.utils.encoding import smart_unicode
|
||||
|
||||
import jinja2
|
||||
import commonware.log
|
||||
from jingo import register
|
||||
from jingo import register, env
|
||||
from tower import ugettext as _
|
||||
|
||||
from amo.utils import memoize
|
||||
|
@ -32,6 +33,22 @@ def file_viewer_class(value, selected):
|
|||
return ' '.join(result)
|
||||
|
||||
|
||||
@register.function
|
||||
def file_tree(files, selected):
|
||||
depth = 0
|
||||
output = ['<ul class="root">']
|
||||
t = env.get_template('files/node.html')
|
||||
for k, v in files.items():
|
||||
if v['depth'] > depth:
|
||||
output.append('<ul class="hidden">')
|
||||
elif v['depth'] < depth:
|
||||
output.extend(['</ul>' for x in range(v['depth'], depth) ])
|
||||
output.append(t.render(value=v, selected=selected))
|
||||
depth = v['depth']
|
||||
output.extend(['</ul>' for x in range(depth, -1, -1) ])
|
||||
return jinja2.Markup('\n'.join(output))
|
||||
|
||||
|
||||
class FileViewer:
|
||||
|
||||
def __init__(self, file_obj):
|
||||
|
@ -123,12 +140,18 @@ class FileViewer:
|
|||
@memoize(prefix='file-viewer')
|
||||
def _get_files(self):
|
||||
all_files, res = [], SortedDict()
|
||||
for root, dirs, files in os.walk(self.dest):
|
||||
for filename in dirs + files:
|
||||
all_files.append([os.path.join(root, filename), filename])
|
||||
# Not using os.path.walk so we get just the right order.
|
||||
|
||||
for path, filename in sorted(all_files):
|
||||
filename = smart_unicode(filename)
|
||||
def iterate(node):
|
||||
for filename in os.listdir(node):
|
||||
full = os.path.join(node, filename)
|
||||
all_files.append(full)
|
||||
if os.path.isdir(full):
|
||||
iterate(full)
|
||||
iterate(self.dest)
|
||||
|
||||
for path in all_files:
|
||||
filename = smart_unicode(os.path.basename(path))
|
||||
short = smart_unicode(path[len(self.dest) + 1:])
|
||||
mime, encoding = mimetypes.guess_type(filename)
|
||||
directory = os.path.isdir(path)
|
||||
|
@ -144,8 +167,8 @@ class FileViewer:
|
|||
'short': short,
|
||||
'truncated': self.truncate(filename),
|
||||
'url': reverse('files.list', args=args),
|
||||
'url_serve': reverse('files.redirect', args=args),
|
||||
'parent': '/'.join(short.split(os.sep)[:-1])}
|
||||
'url_serve': reverse('files.redirect', args=args)}
|
||||
|
||||
return res
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
<li>
|
||||
<a class="{{ file_viewer_class(value, selected) }}"
|
||||
href="{{ value['url'] }}"
|
||||
title="{{ value['filename'] }}">{{ value['truncated'] }}</a>
|
||||
</li>
|
|
@ -7,91 +7,80 @@
|
|||
<a href="{{ file_url }}">{{ addon.name }} {{ version }}</a>
|
||||
{% if file.platform.id != amo.PLATFORM_ALL.id %}({{ file.platform }}){% endif %}
|
||||
</h3>
|
||||
<div id="file-viewer">
|
||||
{% if not status %}
|
||||
<p class="waiting" id="extracting" data-url="{{ poll_url }}">
|
||||
{{ _('Add-on file being processed, please wait.') }}
|
||||
</p>
|
||||
{% endif %}
|
||||
<div id="files">
|
||||
<ul>
|
||||
{% if files %}
|
||||
{% for key, value in files.items() %}
|
||||
<li data-parent="{{ value['parent'] }}"
|
||||
data-short="{{ value['short'] }}"
|
||||
style="padding-left: {{ value['depth'] }}em"
|
||||
class="{% if value['depth'] %}hidden{% endif %}">
|
||||
<a class="{{ file_viewer_class(value, selected) }}"
|
||||
href="{{ value['url'] }}"
|
||||
title="{{ value['filename'] }}">{{ value['truncated'] }}</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</ul>
|
||||
{% if files %}
|
||||
<p>
|
||||
<a href="#" id="files-prev">{{ _('Prev') }}</a> |
|
||||
<a href="#" id="files-next">{{ _('Next') }}</a><br />
|
||||
<a href="#" id="files-expand-all">{{ _('Expand All') }}</a><br />
|
||||
<a href="#" id="files-unwrap">{{ _('Unwrap text')}}</a>
|
||||
<a href="#" id="files-wrap" class="hidden">{{ _('Wrap text')}}</a><br />
|
||||
</p>
|
||||
|
||||
{% elif not files and status %}
|
||||
<p>{{ _('No files in the uploaded file.') }}</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div id="thinking" class="hidden">
|
||||
<p class="waiting">
|
||||
{{ _('Fetching file.') }}
|
||||
</p>
|
||||
</div>
|
||||
<div id="content-wrapper">
|
||||
{% if msg %}
|
||||
<p>{{ msg }}</p>
|
||||
{% endif %}
|
||||
<div>
|
||||
{% if viewer %}
|
||||
{% if selected['binary'] and not selected['directory'] %}
|
||||
{% include "files/file.html" %}
|
||||
{% else %}
|
||||
{% if selected and content %}
|
||||
<pre id="content" class="wrapped">{{ content }}</pre>
|
||||
{% elif content == '' %}
|
||||
<p>{{ _('No content.') }}</p>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if diff and not diff.is_binary() %}
|
||||
{% if text_one and text_two %}
|
||||
<pre id="diff" class="wrapped"></pre>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if diff and diff.is_binary() %}
|
||||
<p>
|
||||
{% if diff.is_different() %}
|
||||
{{ _('Files are different.') }}<br/>
|
||||
{% else %}
|
||||
{{ _('Files are the same.') }}<br/>
|
||||
{% endif %}
|
||||
{% with selected = diff.one, file = diff.file_one.file %}
|
||||
{% include "files/file.html" %}
|
||||
{% endwith %}
|
||||
{% with selected = diff.two, file = diff.file_two.file %}
|
||||
{% include "files/file.html" %}
|
||||
{% endwith %}
|
||||
<ol class="breadcrumbs">
|
||||
<li>{{ addon.name }}</li>
|
||||
<li>{{ version }}</li>
|
||||
<li id="breadcrumb">{{ selected['filename'] }}</li>
|
||||
</ol>
|
||||
<div id="file-viewer" class="featured">
|
||||
<div class="featured-inner">
|
||||
{% if not status %}
|
||||
<p class="waiting" id="extracting" data-url="{{ poll_url }}">
|
||||
{{ _('Add-on file being processed, please wait.') }}
|
||||
</p>
|
||||
{% endif %}
|
||||
{% if diff and not diff.is_binary() %}
|
||||
<div class="hidden">
|
||||
<pre id="file-one">{{ text_one }}</pre>
|
||||
<pre id="file-two">{{ text_two }}</pre>
|
||||
<div id="files">
|
||||
{% if files %}
|
||||
{{ file_tree(files, selected) }}
|
||||
{% endif %}
|
||||
{% if files %}
|
||||
<p id="commands">
|
||||
<code>j</code> <a href="#" id="files-prev">{{ _('Previous file') }}</a><br/>
|
||||
<code>k</code> <a href="#" id="files-next">{{ _('Next file') }}</a><br/>
|
||||
<code>e</code> <a href="#" id="files-expand-all">{{ _('Expand all') }}</a><br/>
|
||||
<code>h</code> <a href="#" id="files-hide">{{ _('Hide or unhide tree') }}</a><br/>
|
||||
<code>w</code> <a href="#" id="files-wrap">{{ _('Wrap or unwrap text') }}</a>
|
||||
</p>
|
||||
{% elif not files and status %}
|
||||
<p>{{ _('No files in the uploaded file.') }}</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div id="thinking" class="hidden">
|
||||
<p class="waiting">
|
||||
{{ _('Fetching file.') }}
|
||||
</p>
|
||||
</div>
|
||||
<div id="content-wrapper">
|
||||
{% if msg %}
|
||||
<p>{{ msg }}</p>
|
||||
{% endif %}
|
||||
<div>
|
||||
{% if viewer %}
|
||||
{% if selected['binary'] and not selected['directory'] %}
|
||||
{% include "files/file.html" %}
|
||||
{% else %}
|
||||
{% if selected and content %}
|
||||
<pre id="content" class="wrapped">{{ content }}</pre>
|
||||
{% elif content == '' %}
|
||||
<p>{{ _('No content.') }}</p>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if diff and diff.is_binary() %}
|
||||
<p>
|
||||
{% if diff.is_different() %}
|
||||
{{ _('Files are different.') }}<br/>
|
||||
{% else %}
|
||||
{{ _('Files are the same.') }}<br/>
|
||||
{% endif %}
|
||||
{% with selected = diff.one, file = diff.file_one.file %}
|
||||
{% include "files/file.html" %}
|
||||
{% endwith %}
|
||||
{% with selected = diff.two, file = diff.file_two.file %}
|
||||
{% include "files/file.html" %}
|
||||
{% endwith %}
|
||||
</p>
|
||||
{% endif %}
|
||||
{% if diff and not diff.is_binary() %}
|
||||
{% if text_one and text_two %}
|
||||
<pre id="diff" class="wrapped hidden"></pre>
|
||||
<pre class="left hidden">{{ text_one }}</pre>
|
||||
<pre class="right hidden">{{ text_two }}</pre>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<p class="help">
|
||||
{{ _('Shortcuts: prev j, next k') }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
|
|
@ -114,13 +114,23 @@ class TestFileHelper(test_utils.TestCase):
|
|||
self.viewer.extract()
|
||||
files = self.viewer.get_files()
|
||||
eq_(files['dictionaries/license.txt']['depth'], 1)
|
||||
eq_(files['dictionaries/license.txt']['parent'], 'dictionaries')
|
||||
|
||||
def test_bom(self):
|
||||
dest = tempfile.mkstemp()[1]
|
||||
open(dest, 'w').write('foo'.encode('utf-16'))
|
||||
eq_(self.viewer.read_file({'full': dest}), (u'foo', ''))
|
||||
|
||||
def test_file_order(self):
|
||||
self.viewer.extract()
|
||||
dest = self.viewer.dest
|
||||
open(os.path.join(dest, 'chrome.manifest'), 'w')
|
||||
subdir = os.path.join(dest, 'chrome')
|
||||
os.mkdir(subdir)
|
||||
open(os.path.join(subdir, 'foo'), 'w')
|
||||
cache.clear()
|
||||
eq_(self.viewer.get_files().keys()[8:11],
|
||||
[u'chrome', u'chrome/foo', u'chrome.manifest'])
|
||||
|
||||
|
||||
class TestDiffHelper(test_utils.TestCase):
|
||||
|
||||
|
|
|
@ -331,8 +331,7 @@ class TestDiffViewer(FilesBase, test_utils.TestCase):
|
|||
self.file_viewer.extract()
|
||||
res = self.client.get(self.file_url(not_binary))
|
||||
doc = pq(res.content)
|
||||
eq_(len(doc('#file-one')), 1)
|
||||
eq_(len(doc('#file-two')), 1)
|
||||
eq_(len(doc('pre')), 3)
|
||||
|
||||
def test_binary_serve_links(self):
|
||||
self.file_viewer.extract()
|
||||
|
|
|
@ -1,123 +1,82 @@
|
|||
#file-viewer {
|
||||
background: white;
|
||||
padding-top: 1em
|
||||
#file-viewer div.featured-inner {
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
#files {
|
||||
width: 20%;
|
||||
display: block;
|
||||
float: left;
|
||||
}
|
||||
|
||||
#files li a {
|
||||
display: inline-block;
|
||||
margin-left: 20px;
|
||||
padding: 2px 5px 2px 15px;
|
||||
}
|
||||
|
||||
#content a {
|
||||
padding: 0em;
|
||||
margin: 0em;
|
||||
#files ul.root {
|
||||
overflow-x: scroll;
|
||||
}
|
||||
|
||||
#content-wrapper, #thinking {
|
||||
width: 50em;
|
||||
float: left;
|
||||
margin-left: 1em;
|
||||
padding-left: 3em;
|
||||
}
|
||||
|
||||
#content div.number, #diff div.number {
|
||||
display: inline;
|
||||
float: left;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
|
||||
#content div.code, #diff div.code {
|
||||
width: 50em;
|
||||
display: block;
|
||||
position: relative;
|
||||
left: 3em;
|
||||
#files ul {
|
||||
padding-left: 1em;
|
||||
}
|
||||
|
||||
.wrapped {
|
||||
#thinking {
|
||||
padding-left: 25%;
|
||||
}
|
||||
|
||||
span.number {
|
||||
width: 4em;
|
||||
display: inline-block;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
pre {
|
||||
overflow-x: scroll;
|
||||
}
|
||||
|
||||
pre.wrapped {
|
||||
white-space: pre-wrap;
|
||||
word-wrap: break-word;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
pre div, pre ins, pre del {
|
||||
display: inline-block;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
pre div:hover, pre ins:hover, pre del:hover {
|
||||
pre div.line:hover {
|
||||
background-color: #ffffcc;
|
||||
}
|
||||
|
||||
pre ins {
|
||||
background-color: #e6ffe6;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
pre del {
|
||||
background-color: #ffe6e6;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
#content, #diff {
|
||||
background: white;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.add {
|
||||
background-color: #ddf8dd;
|
||||
width: 100%;
|
||||
background-color: #e6ffe6;
|
||||
}
|
||||
|
||||
.delete {
|
||||
background-color: #ffdddd;
|
||||
width: 100%;
|
||||
background-color: #ffe6e6;
|
||||
}
|
||||
|
||||
#file-viewer span {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
line-height: 0;
|
||||
}
|
||||
|
||||
#file-viewer li a {
|
||||
margin-left: 20px;
|
||||
padding: 2px 5px 2px 15px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#file-viewer a.selected {
|
||||
a.selected {
|
||||
background-color: #ddf8dd;
|
||||
}
|
||||
|
||||
#file-viewer a.closed {
|
||||
a.closed {
|
||||
background: url('/media/img/icons/plus.gif') 0 no-repeat;
|
||||
}
|
||||
|
||||
#file-viewer a.open {
|
||||
a.open {
|
||||
background: url('/media/img/icons/minus.gif') 0 no-repeat;
|
||||
}
|
||||
|
||||
#file-viewer .waiting {
|
||||
.waiting {
|
||||
background-image: url(../../img/zamboni/loading-white.gif);
|
||||
background-repeat: no-repeat;
|
||||
background-position: left top;
|
||||
padding-left: 2em;
|
||||
}
|
||||
|
||||
#file-viewer p.help {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
dl dt {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
dl dd {
|
||||
padding-left: 1em;
|
||||
code {
|
||||
font-weight: bold;
|
||||
color: white;
|
||||
background-color: darkgrey;
|
||||
padding: 2px 6px 2px 6px;
|
||||
margin: 2px;
|
||||
}
|
||||
|
|
|
@ -19,121 +19,115 @@ if (typeof diff_match_patch !== 'undefined') {
|
|||
for (var t = 0; t < lines.length; t++) {
|
||||
switch (op) {
|
||||
case DIFF_INSERT:
|
||||
html.push(format('<div><div class="number"><a href="#L{0}" name="L{0}">{0}</a>' +
|
||||
'</div><div class="code add">{1}</div></div>', k, lines[t]));
|
||||
// TODO (andym): templates might work here as suggested by cvan
|
||||
html.push(format('<div class="line add"><span class="number"><a href="#L{0}" name="L{0}">{0}</a> +' +
|
||||
'</span><span class="code">{1}</span></div>', k, lines[t]));
|
||||
k++;
|
||||
break;
|
||||
case DIFF_DELETE:
|
||||
html.push(format('<div><div class="number"></div>' +
|
||||
'<div class="code delete">{0}</div></div>', lines[t]));
|
||||
html.push(format('<div class="line delete"><span class="number"> -</span>' +
|
||||
'<span class="code">{0}</span></div>', lines[t]));
|
||||
break;
|
||||
case DIFF_EQUAL:
|
||||
html.push(format('<div><div class="number"><a href="#L{0}" name="L{0}">{0}</a>' +
|
||||
'</div><div class="code">{1}</div></div>', k, lines[t]));
|
||||
html.push(format('<div class="line"><span class="number"><a href="#L{0}" name="L{0}">{0}</a> ' +
|
||||
'</span><span class="code">{1}</span></div>', k, lines[t]));
|
||||
k++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return html.join('\n');
|
||||
return html.join('');
|
||||
};
|
||||
}
|
||||
|
||||
function bind_viewer() {
|
||||
function bind_viewer(nodes) {
|
||||
function Viewer() {
|
||||
this.$tree = $('#files ul');
|
||||
this.compute = function() {
|
||||
var node = $('#content');
|
||||
if (node.length) {
|
||||
var splitted = node.text().split('\n'),
|
||||
this.nodes = nodes;
|
||||
this.wrapped = true;
|
||||
this.hidden = false;
|
||||
this.compute = function(node) {
|
||||
var $content = node.find('#content'),
|
||||
$diff = node.find('#diff');
|
||||
if ($content.length) {
|
||||
var splitted = $content.text().split('\n'),
|
||||
length = splitted.length,
|
||||
html = [];
|
||||
if (splitted.splice(length-1, length) == '') {
|
||||
if (splitted.slice(length-1) == '') {
|
||||
length = length - 1;
|
||||
}
|
||||
for (var k = 0; k < splitted.length; k++) {
|
||||
var text = splitted[k].replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
||||
html.push(format('<div><div class="number"><a href="#L{0}" name="L{0}">{0}</a></div>' +
|
||||
'<div class="code">{1}</div></div>', k+1, text));
|
||||
for (var k = 0; k < length; k++) {
|
||||
if (splitted[k] !== undefined) {
|
||||
var text = splitted[k].replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
||||
html.push(format('<div class="line"><span class="number"><a href="#L{0}" name="L{0}">{0}</a></span>' +
|
||||
'<span class="code"> {1}</span></div>', k+1, text));
|
||||
}
|
||||
}
|
||||
node.html(html.join('\n'));
|
||||
$content.html(html.join('')).removeClass('hidden').show();
|
||||
}
|
||||
|
||||
if ($('#diff').length) {
|
||||
if ($diff.length) {
|
||||
var dmp = new diff_match_patch();
|
||||
var diff = dmp.diff_main($('#file-one').text(), $('#file-two').text());
|
||||
$('#diff').html(dmp.diff_prettyHtml(diff));
|
||||
var diff = dmp.diff_main($diff.siblings('.left').text(), $diff.siblings('.right').text());
|
||||
$diff.html(dmp.diff_prettyHtml(diff)).removeClass('hidden').show();
|
||||
}
|
||||
|
||||
if (window.location.hash) {
|
||||
window.location = window.location;
|
||||
}
|
||||
this.$tree.show();
|
||||
};
|
||||
this.show_leaf = function(names) {
|
||||
/* Exposes the leaves for a given set of nodes. */
|
||||
this.$tree.find('li').each(function() {
|
||||
var $this = $(this),
|
||||
parent = $this.attr('data-parent'),
|
||||
shrt = $this.attr('data-short'),
|
||||
a = $this.find('a');
|
||||
|
||||
if (parent && (names.indexOf(parent) > -1) &&
|
||||
$this.hasClass('hidden')) {
|
||||
$this.removeClass('hidden').show();
|
||||
}
|
||||
|
||||
else if (names.length === 1 &&
|
||||
(shrt.length > names[0].length) &&
|
||||
(shrt.indexOf(names[0]) === 0)) {
|
||||
$this.addClass('hidden').hide();
|
||||
if (a.hasClass('open')) {
|
||||
a.removeClass('open').addClass('closed');
|
||||
}
|
||||
}
|
||||
|
||||
if (names.indexOf($this.attr('data-short')) > -1) {
|
||||
if (a.hasClass('closed')) {
|
||||
a.removeClass('closed').addClass('open');
|
||||
}
|
||||
}
|
||||
});
|
||||
this.toggle_leaf = function($leaf) {
|
||||
if ($leaf.hasClass('open')) {
|
||||
this.hide_leaf($leaf);
|
||||
} else {
|
||||
this.show_leaf($leaf);
|
||||
}
|
||||
};
|
||||
this.hide_leaf = function($leaf) {
|
||||
$leaf.removeClass('open').addClass('closed')
|
||||
.closest('li').next('ul')
|
||||
.addClass('hidden').hide();
|
||||
};
|
||||
this.show_leaf = function($leaf) {
|
||||
/* Exposes the leaves for a given set of node. */
|
||||
$leaf.removeClass('closed').addClass('open')
|
||||
.closest('li').next('ul')
|
||||
.removeClass('hidden').show();
|
||||
};
|
||||
this.selected = function($link) {
|
||||
/* Updates the tree, showing the leaves relevant to node */
|
||||
var $curr = $link.closest('li'),
|
||||
leaf = $curr.attr('data-parent').split('/'),
|
||||
names = [];
|
||||
$curr.removeClass('hidden').show();
|
||||
if (leaf.length && (leaf[0])) {
|
||||
for (var k = 0; k <= leaf.length; k += 1) {
|
||||
names.push(leaf.slice(0, k).join('/'));
|
||||
}
|
||||
this.show_leaf(names);
|
||||
}
|
||||
/* Exposes all the leaves to an element */
|
||||
$link.parentsUntil('ul.root').filter('ul')
|
||||
.removeClass('hidden').show()
|
||||
.each(function() {
|
||||
$(this).prev('li').find('a:first')
|
||||
.removeClass('closed').addClass('open');
|
||||
});
|
||||
};
|
||||
this.load = function($link) {
|
||||
/* Accepts a jQuery wrapped node, which is part of the tree.
|
||||
Hides content, shows spinner, gets the content and then
|
||||
shows it all. */
|
||||
shows it all. Then alters the title. */
|
||||
var self = this,
|
||||
$thinking = $('#thinking'),
|
||||
$wrapper = $('#content-wrapper');
|
||||
$wrapper.hide();
|
||||
$thinking.removeClass('hidden').show();
|
||||
$old_wrapper = $('#content-wrapper');
|
||||
$old_wrapper.hide();
|
||||
this.nodes.$thinking.removeClass('hidden').show();
|
||||
if (history.pushState !== undefined) {
|
||||
history.pushState({ path: $link.text() }, '', $link.attr('href'));
|
||||
}
|
||||
$('#content-wrapper').load($link.attr('href') + ' #content-wrapper', function() {
|
||||
$old_wrapper.load($link.attr('href') + ' #content-wrapper', function() {
|
||||
$(this).children().unwrap();
|
||||
self.compute();
|
||||
$thinking.hide();
|
||||
$wrapper.slideDown();
|
||||
var $new_wrapper = $('#content-wrapper');
|
||||
self.compute($new_wrapper);
|
||||
self.nodes.$thinking.hide();
|
||||
$new_wrapper.slideDown();
|
||||
if (self.hidden) {
|
||||
self.toggle_files('hide');
|
||||
}
|
||||
});
|
||||
this.nodes.$title.text($link.closest('li').attr('data-short'));
|
||||
};
|
||||
this.select = function($link) {
|
||||
/* Given a node, alters the tree and then loads the content. */
|
||||
this.$tree.find('a.selected').each(function() {
|
||||
this.nodes.$files.find('a.selected').each(function() {
|
||||
$(this).removeClass('selected');
|
||||
});
|
||||
$link.addClass('selected');
|
||||
|
@ -141,72 +135,94 @@ function bind_viewer() {
|
|||
this.load($link);
|
||||
};
|
||||
this.get_selected = function() {
|
||||
return this.$tree.find('a.selected');
|
||||
var k = 0;
|
||||
$.each(this.nodes.$files.find('a.file'), function(i, el) {
|
||||
if ($(el).hasClass("selected")) {
|
||||
k = i;
|
||||
}
|
||||
});
|
||||
return k;
|
||||
};
|
||||
this.toggle_wrap = function(state) {
|
||||
this.wrapped = (state == 'wrap' || !this.wrapped);
|
||||
$('pre').toggleClass('wrapped', this.wrapped);
|
||||
};
|
||||
this.toggle_files = function(state) {
|
||||
this.hidden = (state == 'hide' || !this.hidden);
|
||||
if (this.hidden) {
|
||||
this.nodes.$files.hide();
|
||||
this.nodes.$commands.detach().appendTo('#content-wrapper');
|
||||
} else {
|
||||
this.nodes.$files.show();
|
||||
this.nodes.$commands.detach().appendTo('#files');
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
var viewer = new Viewer();
|
||||
|
||||
viewer.$tree.find('.directory').click(_pd(function() {
|
||||
viewer.show_leaf([$(this).closest('li').attr('data-short')]);
|
||||
viewer.nodes.$files.find('.directory').click(_pd(function() {
|
||||
viewer.toggle_leaf($(this));
|
||||
}));
|
||||
|
||||
$('#files-prev').click(_pd(function() {
|
||||
var $curr = viewer.get_selected().closest('li'),
|
||||
choices = $curr.prevUntil('ul').find('a.file');
|
||||
if (choices.length) { viewer.select($(choices[0])); }
|
||||
viewer.select(viewer.nodes.$files.find('a.file').eq(viewer.get_selected() - 1));
|
||||
}));
|
||||
|
||||
$('#files-next').click(_pd(function() {
|
||||
var $curr = viewer.get_selected().closest('li'),
|
||||
choices = $curr.nextUntil('ul').find('a.file');
|
||||
if (choices.length) { viewer.select($(choices[0])); }
|
||||
viewer.select(viewer.nodes.$files.find('a.file').eq(viewer.get_selected() + 1));
|
||||
}));
|
||||
|
||||
$('#files-wrap').click(_pd(function() {
|
||||
$('pre').addClass('wrapped');
|
||||
$('#files-wrap').hide();
|
||||
$('#files-unwrap').removeClass('hidden').show();
|
||||
viewer.toggle_wrap();
|
||||
}));
|
||||
|
||||
$('#files-unwrap').click(_pd(function() {
|
||||
$('pre').removeClass('wrapped');
|
||||
$('#files-wrap').removeClass('hidden').show();
|
||||
$('#files-unwrap').hide();
|
||||
$('#files-hide').click(_pd(function() {
|
||||
viewer.toggle_files();
|
||||
}));
|
||||
|
||||
$('#files-expand-all').click(_pd(function() {
|
||||
viewer.$tree.find('li.hidden').removeClass('hidden').show();
|
||||
viewer.$tree.find('a.directory').removeClass('closed').addClass('open');
|
||||
viewer.nodes.$files.find('a.closed').each(function() {
|
||||
viewer.show_leaf($(this));
|
||||
});
|
||||
}));
|
||||
|
||||
viewer.$tree.find('.file').click(_pd(function() {
|
||||
viewer.nodes.$files.find('.file').click(_pd(function() {
|
||||
viewer.select($(this));
|
||||
$('#files-unwrap').removeClass('hidden').show();
|
||||
$('#files-wrap').hide();
|
||||
viewer.toggle_wrap('wrap');
|
||||
}));
|
||||
|
||||
$(document).bind('keyup', _pd(function(e) {
|
||||
if (e.keyCode === 75) {
|
||||
if (e.keyCode == 72) {
|
||||
$('#files-hide').trigger('click');
|
||||
} else if (e.keyCode == 75) {
|
||||
$('#files-next').trigger('click');
|
||||
} else if (e.keyCode === 74) {
|
||||
} else if (e.keyCode == 74) {
|
||||
$('#files-prev').trigger('click');
|
||||
} else if (e.keyCode == 87) {
|
||||
$('#files-wrap').trigger('click');
|
||||
} else if (e.keyCode == 69) {
|
||||
$('#files-expand-all').trigger('click');
|
||||
}
|
||||
}));
|
||||
|
||||
return viewer;
|
||||
}
|
||||
|
||||
$(document).ready(function() {
|
||||
var viewer = null;
|
||||
|
||||
var nodes = {
|
||||
$files: $('#files'),
|
||||
$thinking: $('#thinking'),
|
||||
$title: $('#breadcrumb'),
|
||||
$commands: $('#commands')
|
||||
};
|
||||
function poll_file_extraction() {
|
||||
$.getJSON($('#extracting').attr('data-url'), function(json) {
|
||||
if (json && json.status) {
|
||||
$('#file-viewer').load(window.location.pathname + ' #file-viewer', function() {
|
||||
viewer = bind_viewer();
|
||||
viewer = bind_viewer(nodes);
|
||||
viewer.selected(viewer.$tree.find('a.selected'));
|
||||
viewer.compute();
|
||||
viewer.compute($('#content-wrapper'));
|
||||
});
|
||||
} else {
|
||||
setTimeout(poll_file_extraction, 2000);
|
||||
|
@ -217,8 +233,8 @@ $(document).ready(function() {
|
|||
if ($('#extracting').length) {
|
||||
poll_file_extraction();
|
||||
} else if ($('#file-viewer').length) {
|
||||
viewer = bind_viewer();
|
||||
viewer.selected(viewer.$tree.find('a.selected'));
|
||||
viewer.compute();
|
||||
viewer = bind_viewer(nodes);
|
||||
viewer.selected(viewer.nodes.$files.find('a.selected'));
|
||||
viewer.compute($('#content-wrapper'));
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1,12 +1,25 @@
|
|||
$(document).ready(function(){
|
||||
var fileViewer = {
|
||||
setup: function() {
|
||||
this.sandbox = tests.createSandbox('#files-wrapper');
|
||||
},
|
||||
teardown: function() {
|
||||
this.sandbox.remove();
|
||||
}
|
||||
};
|
||||
|
||||
module('File viewer');
|
||||
module('File viewer', fileViewer);
|
||||
|
||||
test('Show leaf', function() {
|
||||
var viewer = bind_viewer();
|
||||
viewer.show_leaf(['foo']);
|
||||
equal($($('#files li a')[1]).hasClass('open'), true);
|
||||
equal($($('#files li')[2]).hasClass('hidden'), false);
|
||||
var nodes = {
|
||||
$files: this.sandbox.find($('#files'))
|
||||
};
|
||||
var viewer = bind_viewer(nodes);
|
||||
viewer.toggle_leaf(this.sandbox.find('a.directory'));
|
||||
equal(this.sandbox.find('a.directory').hasClass('open'), true);
|
||||
equal(this.sandbox.find('ul').hasClass('hidden'), false);
|
||||
viewer.toggle_leaf(this.sandbox.find('a.directory'));
|
||||
equal(this.sandbox.find('a.directory').hasClass('open'), false);
|
||||
equal(this.sandbox.find('ul').hasClass('hidden'), true);
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
@ -255,18 +255,22 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="files">
|
||||
<div id="files-wrapper">
|
||||
<div id="files>
|
||||
<ul>
|
||||
<li class="" style="padding-left: 0em;" data-parent="" data-short="someurl">
|
||||
<li>
|
||||
<a class="file" href="">someurl</a>
|
||||
</li>
|
||||
<li style="padding-left: 1em; display: list-item;" data-parent="" data-short="foo">
|
||||
<li>
|
||||
<a class="directory closed" href="">foo</a>
|
||||
</li>
|
||||
<li class="hidden" style="padding-left: 1em; display: list-item;" data-parent="foo" data-short="foo/bar.txt">
|
||||
<a class="file" href="someurl">foo/bar.txt</a>
|
||||
</li>
|
||||
<ul class="hidden">
|
||||
<li>
|
||||
<a class="file" href="someurl">foo/bar.txt</a>
|
||||
</li>
|
||||
</ul>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div id="paypal">
|
||||
<div class="contribute">
|
||||
|
|
Загрузка…
Ссылка в новой задаче