Changeset - 47e54cf3047b
[Not reviewed]
default
0 3 0
Martin Vium - 12 years ago 2013-11-12 11:10:38
martinv@unity3d.com
files: preview of images
3 files changed with 23 insertions and 7 deletions:
0 comments (0 inline, 0 general)
kallithea/lib/vcs/nodes.py
Show inline comments
 
@@ -329,192 +329,200 @@ class FileNode(Node):
 
                                'element list or tuple')
 

	
 
        mtype, encoding = mimetypes.guess_type(self.name)
 

	
 
        if mtype is None:
 
            if self.is_binary:
 
                mtype = 'application/octet-stream'
 
                encoding = None
 
            else:
 
                mtype = 'text/plain'
 
                encoding = None
 

	
 
                #try with pygments
 
                try:
 
                    from pygments.lexers import get_lexer_for_filename
 
                    mt = get_lexer_for_filename(self.name).mimetypes
 
                except Exception:
 
                    mt = None
 

	
 
                if mt:
 
                    mtype = mt[0]
 

	
 
        return mtype, encoding
 

	
 
    @LazyProperty
 
    def mimetype(self):
 
        """
 
        Wrapper around full mimetype info. It returns only type of fetched
 
        mimetype without the encoding part. use get_mimetype function to fetch
 
        full set of (type,encoding)
 
        """
 
        return self.get_mimetype()[0]
 

	
 
    @LazyProperty
 
    def mimetype_main(self):
 
        return self.mimetype.split('/')[0]
 

	
 
    @LazyProperty
 
    def lexer(self):
 
        """
 
        Returns pygment's lexer class. Would try to guess lexer taking file's
 
        content, name and mimetype.
 
        """
 
        from pygments import lexers
 
        try:
 
            lexer = lexers.guess_lexer_for_filename(self.name, self.content, stripnl=False)
 
        except lexers.ClassNotFound:
 
            lexer = lexers.TextLexer(stripnl=False)
 
        # returns first alias
 
        return lexer
 

	
 
    @LazyProperty
 
    def lexer_alias(self):
 
        """
 
        Returns first alias of the lexer guessed for this file.
 
        """
 
        return self.lexer.aliases[0]
 

	
 
    @LazyProperty
 
    def history(self):
 
        """
 
        Returns a list of changeset for this file in which the file was changed
 
        """
 
        if self.changeset is None:
 
            raise NodeError('Unable to get changeset for this FileNode')
 
        return self.changeset.get_file_history(self.path)
 

	
 
    @LazyProperty
 
    def annotate(self):
 
        """
 
        Returns a list of three element tuples with lineno,changeset and line
 
        """
 
        if self.changeset is None:
 
            raise NodeError('Unable to get changeset for this FileNode')
 
        return self.changeset.get_file_annotate(self.path)
 

	
 
    @LazyProperty
 
    def state(self):
 
        if not self.changeset:
 
            raise NodeError("Cannot check state of the node if it's not "
 
                "linked with changeset")
 
        elif self.path in (node.path for node in self.changeset.added):
 
            return NodeState.ADDED
 
        elif self.path in (node.path for node in self.changeset.changed):
 
            return NodeState.CHANGED
 
        else:
 
            return NodeState.NOT_CHANGED
 

	
 
    @property
 
    def is_binary(self):
 
        """
 
        Returns True if file has binary content.
 
        """
 
        _bin = '\0' in self._get_content()
 
        return _bin
 

	
 
    def is_browser_compatible_image(self):
 
        return self.mimetype in [
 
            "image/gif",
 
            "image/jpeg",
 
            "image/png",
 
            "image/bmp"
 
        ]
 

	
 
    @LazyProperty
 
    def extension(self):
 
        """Returns filenode extension"""
 
        return self.name.split('.')[-1]
 

	
 
    @property
 
    def is_executable(self):
 
        """
 
        Returns ``True`` if file has executable flag turned on.
 
        """
 
        return bool(self.mode & stat.S_IXUSR)
 

	
 
    def __repr__(self):
 
        return '<%s %r @ %s>' % (self.__class__.__name__, self.path,
 
                                 getattr(self.changeset, 'short_id', ''))
 

	
 

	
 
class RemovedFileNode(FileNode):
 
    """
 
    Dummy FileNode class - trying to access any public attribute except path,
 
    name, kind or state (or methods/attributes checking those two) would raise
 
    RemovedFileNodeError.
 
    """
 
    ALLOWED_ATTRIBUTES = [
 
        'name', 'path', 'state', 'is_root', 'is_file', 'is_dir', 'kind',
 
        'added', 'changed', 'not_changed', 'removed'
 
    ]
 

	
 
    def __init__(self, path):
 
        """
 
        :param path: relative path to the node
 
        """
 
        super(RemovedFileNode, self).__init__(path=path)
 

	
 
    def __getattribute__(self, attr):
 
        if attr.startswith('_') or attr in RemovedFileNode.ALLOWED_ATTRIBUTES:
 
            return super(RemovedFileNode, self).__getattribute__(attr)
 
        raise RemovedFileNodeError("Cannot access attribute %s on "
 
            "RemovedFileNode" % attr)
 

	
 
    @LazyProperty
 
    def state(self):
 
        return NodeState.REMOVED
 

	
 

	
 
class DirNode(Node):
 
    """
 
    DirNode stores list of files and directories within this node.
 
    Nodes may be used standalone but within repository context they
 
    lazily fetch data within same repositorty's changeset.
 
    """
 

	
 
    def __init__(self, path, nodes=(), changeset=None):
 
        """
 
        Only one of ``nodes`` and ``changeset`` may be given. Passing both
 
        would raise ``NodeError`` exception.
 

	
 
        :param path: relative path to the node
 
        :param nodes: content may be passed to constructor
 
        :param changeset: if given, will use it to lazily fetch content
 
        :param size: always 0 for ``DirNode``
 
        """
 
        if nodes and changeset:
 
            raise NodeError("Cannot use both nodes and changeset")
 
        super(DirNode, self).__init__(path, NodeKind.DIR)
 
        self.changeset = changeset
 
        self._nodes = nodes
 

	
 
    @LazyProperty
 
    def content(self):
 
        raise NodeError("%s represents a dir and has no ``content`` attribute"
 
            % self)
 

	
 
    @LazyProperty
 
    def nodes(self):
 
        if self.changeset:
 
            nodes = self.changeset.get_nodes(self.path)
 
        else:
 
            nodes = self._nodes
 
        self._nodes_dict = dict((node.path, node) for node in nodes)
 
        return sorted(nodes)
 

	
 
    @LazyProperty
 
    def files(self):
 
        return sorted((node for node in self.nodes if node.is_file()))
 

	
 
    @LazyProperty
 
    def dirs(self):
 
        return sorted((node for node in self.nodes if node.is_dir()))
 

	
 
    def __iter__(self):
 
        for node in self.nodes:
 
            yield node
 

	
 
    def get_node(self, path):
 
        """
kallithea/public/css/style.css
Show inline comments
 
@@ -5029,110 +5029,116 @@ table.code-difftable td.code pre u {
 
    color: rgba(0,0,0,0.15);
 
}
 
table.code-highlighttable div.code-highlight pre i,
 
table.code-difftable td.code pre i {
 
    border-style: solid;
 
    border-left-width: 1px;
 
    color: rgba(0,0,0,0.15);
 
}
 

	
 
/** LINE NUMBERS **/
 
table.code-difftable .lineno {
 
    padding-left: 2px;
 
    padding-right: 2px !important;
 
    text-align: right;
 
    width: 30px;
 
    -moz-user-select: none;
 
    -webkit-user-select: none;
 
    border-right: 1px solid #CCC !important;
 
    border-left: 0px solid #CCC !important;
 
    border-top: 0px solid #CCC !important;
 
    border-bottom: none !important;
 
    vertical-align: middle !important;
 
}
 
table.code-difftable .lineno.new {
 
}
 
table.code-difftable .lineno.old {
 
}
 
table.code-difftable .lineno a {
 
    color: #aaa !important;
 
    font: 11px Consolas, Monaco, Inconsolata, Liberation Mono, monospace !important;
 
    letter-spacing: -1px;
 
    text-align: right;
 
    padding-right: 2px;
 
    cursor: pointer;
 
    display: block;
 
    width: 30px;
 
}
 

	
 
table.code-difftable .lineno-inline {
 
    background: none repeat scroll 0 0 #FFF !important;
 
    padding-left: 2px;
 
    padding-right: 2px;
 
    text-align: right;
 
    width: 30px;
 
    -moz-user-select: none;
 
    -webkit-user-select: none;
 
}
 

	
 
/** CODE **/
 
table.code-difftable .code {
 
    display: block;
 
    width: 100%;
 
}
 
table.code-difftable .code td {
 
    margin: 0;
 
    padding: 0;
 
}
 
table.code-difftable .code pre {
 
    margin: 0;
 
    padding: 0;
 
    height: 17px;
 
    line-height: 17px;
 
}
 

	
 
.add-bubble {
 
    display: none;
 
    float: left;
 
    width: 0px;
 
    height: 0px;
 
}
 

	
 
tr.line.add td.code:hover .add-bubble,
 
tr.line.del td.code:hover .add-bubble,
 
tr.line.unmod td.code:hover .add-bubble {
 
    display: inherit;
 
}
 

	
 
.add-bubble div {
 
    position: relative;
 
    left: -32px;
 
    width: 32px;
 
    top: -8px;
 
    height: 32px;
 
    background: url("../images/icons/comment_add.png") no-repeat 100% 50%;
 
    cursor: pointer;
 
}
 

	
 
div.comment:target>.comment-wrapp {
 
    border: solid 2px #ee0 !important;
 
}
 

	
 
.lineno:target a {
 
    border: solid 2px #ee0 !important;
 
    margin: -2px;
 
}
 

	
 
.img-preview {
 
    max-width: 100%;
 
    height: auto;
 
    margin: 5px;
 
}
 

	
 
div.prev-next-comment div.prev-comment,
 
div.prev-next-comment div.next-comment {
 
    display: inline-block;
 
    min-width: 150px;
 
    margin: 3px 6px;
 
}
 

	
 
#help_kb {
 
    display: none;
 
}
 

	
 
.repo-switcher-dropdown .select2-result-label span.repo-icons {
 
    margin-left: -12px;
 
}
kallithea/templates/files/files_source.html
Show inline comments
 
<div id="node_history" style="padding: 0px 0px 10px 0px">
 
    <div>
 
        <div style="float:left">
 
        ${h.form(h.url('files_diff_home',repo_name=c.repo_name,f_path=c.f_path),method='get')}
 
        ${h.hidden('diff2',c.file_changeset.raw_id)}
 
        ${h.hidden('diff1')}
 
        ${h.submit('diff',_('Diff to Revision'),class_="btn btn-small")}
 
        ${h.submit('show_rev',_('Show at Revision'),class_="btn btn-small")}
 
        ${h.hidden('annotate', c.annotate)}
 
        ${h.link_to(_('Show Full History'),h.url('changelog_file_home',repo_name=c.repo_name, revision=c.file_changeset.raw_id, f_path=c.f_path),class_="btn btn-small")}
 
        ${h.link_to(_('Show Authors'),'#',class_="btn btn-small" ,id="show_authors")}
 

	
 
        ${h.end_form()}
 
        </div>
 
        <div id="file_authors" class="file_author" style="clear:both; display: none"></div>
 
    </div>
 
    <div style="clear:both"></div>
 
</div>
 

	
 

	
 
<div id="body" class="codeblock">
 
    <div class="code-header">
 
        <div class="stats">
 
            <div class="left img"><i class="icon-file"></i></div>
 
            <div class="left item"><pre class="tooltip" title="${h.tooltip(h.fmt_date(c.file_changeset.date))}">${h.link_to(h.show_id(c.file_changeset),h.url('changeset_home',repo_name=c.repo_name,revision=c.file_changeset.raw_id))}</pre></div>
 
            <div class="left item"><pre>${h.format_byte_size(c.file.size,binary=True)}</pre></div>
 
            <div class="left item last"><pre>${c.file.mimetype}</pre></div>
 
            <div class="buttons">
 
              %if c.annotate:
 
                ${h.link_to(_('Show Source'),    h.url('files_home',         repo_name=c.repo_name,revision=c.file_changeset.raw_id,f_path=c.f_path),class_="btn btn-mini")}
 
              %else:
 
                ${h.link_to(_('Show Annotation'),h.url('files_annotate_home',repo_name=c.repo_name,revision=c.file_changeset.raw_id,f_path=c.f_path),class_="btn btn-mini")}
 
              %endif
 
              ${h.link_to(_('Show as Raw'),h.url('files_raw_home',repo_name=c.repo_name,revision=c.file_changeset.raw_id,f_path=c.f_path),class_="btn btn-mini")}
 
              ${h.link_to(_('Download as Raw'),h.url('files_rawfile_home',repo_name=c.repo_name,revision=c.file_changeset.raw_id,f_path=c.f_path),class_="btn btn-mini")}
 
              % if h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name):
 
               %if c.on_branch_head and c.changeset.branch and not c.file.is_binary:
 
                ${h.link_to(_('Edit on Branch:%s') % c.changeset.branch, h.url('files_edit_home',repo_name=c.repo_name,revision=c.changeset.branch,f_path=c.f_path, anchor='edit'),class_="btn btn-mini")}
 
                ${h.link_to(_('Delete'), h.url('files_delete_home',repo_name=c.repo_name,revision=c.changeset.branch,f_path=c.f_path, anchor='edit'),class_="btn btn-mini btn-danger")}
 
               %elif c.on_branch_head and c.changeset.branch and c.file.is_binary:
 
                ${h.link_to(_('Edit'), '#', class_="btn btn-mini disabled tooltip", title=_('Editing binary files not allowed'))}
 
                ${h.link_to(_('Delete'), h.url('files_delete_home',repo_name=c.repo_name,revision=c.changeset.branch,f_path=c.f_path, anchor='edit'),class_="btn btn-mini btn-danger")}
 
               %else:
 
                ${h.link_to(_('Edit'), '#', class_="btn btn-mini disabled tooltip", title=_('Editing files allowed only when on branch head revision'))}
 
                ${h.link_to(_('Delete'), '#', class_="btn btn-mini btn-danger disabled tooltip", title=_('Deleting files allowed only when on branch head revision'))}
 
               % endif
 
              % endif
 
            </div>
 
        </div>
 
        <div class="author">
 
            <div class="gravatar">
 
                <img alt="gravatar" src="${h.gravatar_url(h.email_or_none(c.file_changeset.author),16)}"/>
 
            </div>
 
            <div title="${c.file_changeset.author}" class="user">${h.person(c.file_changeset.author)}</div>
 
        </div>
 
        <div class="commit">${h.urlify_commit(c.file_changeset.message,c.repo_name)}</div>
 
    </div>
 
    <div class="code-body">
 
       %if c.file.is_binary:
 
           <div style="padding:5px">
 
           ${_('Binary file (%s)') % c.file.mimetype}
 
           </div>
 
       %else:
 
        % if c.file.size < c.cut_off_limit:
 
      %if c.file.is_browser_compatible_image():
 
        <img src="${h.url('files_raw_home',repo_name=c.repo_name,revision=c.file_changeset.raw_id,f_path=c.f_path)}" class="img-preview"/>
 
      %elif c.file.is_binary:
 
        <div style="padding:5px">
 
          ${_('Binary file (%s)') % c.file.mimetype}
 
        </div>
 
      %else:
 
        %if c.file.size < c.cut_off_limit:
 
            %if c.annotate:
 
              ${h.pygmentize_annotation(c.repo_name,c.file,linenos=True,anchorlinenos=True,lineanchors='L',cssclass="code-highlight")}
 
            %else:
 
              ${h.pygmentize(c.file,linenos=True,anchorlinenos=True,lineanchors='L',cssclass="code-highlight")}
 
            %endif
 
        %else:
 
            ${_('File is too big to display')} ${h.link_to(_('Show as raw'),
 
            h.url('files_raw_home',repo_name=c.repo_name,revision=c.file_changeset.raw_id,f_path=c.f_path))}
 
        %endif
 
     %endif
 
      %endif
 
    </div>
 
</div>
 

	
 
<script>
 
    $(document).ready(function(){
 
        // fake html5 history state
 
        var _State = {
 
           url: "${h.url.current()}",
 
           data: {
 
             node_list_url: node_list_url.replace('__REV__',"${c.changeset.raw_id}").replace('__FPATH__', "${h.safe_unicode(c.file.path)}"),
 
             url_base: url_base.replace('__REV__',"${c.changeset.raw_id}"),
 
             rev:"${c.changeset.raw_id}",
 
             f_path: "${h.safe_unicode(c.file.path)}"
 
           }
 
        }
 
        callbacks(_State) // defined in files.html, main callbacks. Triggerd in pjax calls
 
    })
 
</script>
0 comments (0 inline, 0 general)