Newer
Older
GitBucket / src / main / twirl / gitbucket / core / repo / blob.scala.html
@nazoking nazoking on 27 Mar 2015 9 KB follow rename
@(branch: String,
  repository: gitbucket.core.service.RepositoryService.RepositoryInfo,
  pathList: List[String],
  content: gitbucket.core.util.JGitUtil.ContentInfo,
  latestCommit: gitbucket.core.util.JGitUtil.CommitInfo,
  hasWritePermission: Boolean,
  isBlame: Boolean)(implicit context: gitbucket.core.controller.Context)
@import context._
@import gitbucket.core.view.helpers._
@html.main(s"${repository.owner}/${repository.name}", Some(repository)) {
  @html.menu("code", repository){
    <div class="head">
      <div class="line-age-legend">
        <span>Newer</span>
        <ol>
            <li class="heat1"></li>
            <li class="heat2"></li>
            <li class="heat3"></li>
            <li class="heat4"></li>
            <li class="heat5"></li>
            <li class="heat6"></li>
            <li class="heat7"></li>
            <li class="heat8"></li>
            <li class="heat9"></li>
            <li class="heat10"></li>
        </ol>
        <span>Older</span>
      </div>
      @helper.html.branchcontrol(
        branch,
        repository,
        hasWritePermission
      ){
        @repository.branchList.map { x =>
          <li><a href="@url(repository)/blob/@encodeRefName(x)/@pathList.mkString("/")">@helper.html.checkicon(x == branch) @x</a></li>
        }
      }
      <a href="@url(repository)/tree/@encodeRefName(branch)">@repository.name</a> /
      @pathList.zipWithIndex.map { case (section, i) =>
        @if(i == pathList.length - 1){
          @section
        } else {
          <a href="@url(repository)/tree/@encodeRefName(branch)/@pathList.take(i + 1).mkString("/")">@section</a> /
        }
      }
    </div>

    <table class="table table-bordered blobview">
      <tr>
        <th style="font-weight: normal;">
          <div class="pull-left">
            @avatar(latestCommit, 20)
            @user(latestCommit.authorName, latestCommit.authorEmailAddress, "username strong")
            <span class="muted">@helper.html.datetimeago(latestCommit.commitTime)</span>
            <a href="@url(repository)/commit/@latestCommit.id" class="commit-message">@link(latestCommit.summary, repository)</a>
          </div>
          <div class="btn-group pull-right">
            @if(hasWritePermission && content.viewType == "text" && repository.branchList.contains(branch)){
              <a class="btn btn-mini" href="@url(repository)/edit/@encodeRefName(branch)/@pathList.mkString("/")">Edit</a>
            }
            <a class="btn btn-mini" href="?raw=true">Raw</a>
            @if(content.viewType == "text"){
              <a class="btn btn-mini blame-action" href="@url(repository)/blame/@latestCommit.id/@pathList.mkString("/")" data-url="@url(repository)/get-blame/@latestCommit.id/@pathList.mkString("/")" data-repository="@url(repository)">Blame</a>
            }
            <a class="btn btn-mini" href="@url(repository)/commits/@encodeRefName(branch)/@pathList.mkString("/")">History</a>
            @if(hasWritePermission){
              <a class="btn btn-mini btn-danger" href="@url(repository)/remove/@encodeRefName(branch)/@pathList.mkString("/")">Delete</a>
            }
          </div>
        </th>
      </tr>
      <tr>
        <td>
          @if(content.viewType == "text"){
            @defining(renderableSuffixes.find(suffix => pathList.reverse.head.toLowerCase.endsWith(suffix))) { isRrenderable =>
              @if(!isBlame && isRrenderable) {
                <div class="box-content markdown-body" style="border: none; padding-left: 16px; padding-right: 16px;">
                  @renderMarkup(pathList, content.content.get, branch, repository, false, false)
                </div>
              } else {
                <pre class="prettyprint linenums blob @if(!isRrenderable){ no-renderable } ">@content.content.get</pre>
              }
            }
          }
          @if(content.viewType == "image"){
            <img src="?raw=true"/>
          }
          @if(content.viewType == "large" || content.viewType == "binary"){
            <div style="text-align: center; padding-top: 20px; padding-bottom: 20px;">
              <a href="?raw=true">View Raw</a><br>
              <br>
              (Sorry about that, but we can't show files that are this big right now)
            </div>
          }
        </td>
      </tr>
    </table>
  }
}
<script src="@assets/vendors/jquery/jquery.ba-hashchange.js"></script>
<script>
$(window).load(function(){
  $(window).hashchange(function(){
    updateHighlighting();
  }).hashchange();

  var pre = $('pre.prettyprint');
  function updateSourceLineNum(){
    $('.source-line-num').remove();
    var pos = pre.find('ol.linenums').position();
    $('<div class="source-line-num">').css({
      height:pre.height(),
      width:'48px',
      cursor:'pointer',
      position: 'absolute',
      top     : pos.top + 'px',
      left    : pos.left + 'px'
    }).click(function(e){
      $(window).hashchange(function(){})
      var pos = $(this).data("pos");
      if(!pos){
        pos = $('ol.linenums li').map(function(){ return {id:$(this).attr("id"),top:$(this).position().top} }).toArray();
        $(this).data("pos",pos);
      }
      for(var i=0;i<pos.length-1;i++){
        if(pos[i+1].top>e.pageY){
          break;
        }
      }
      var line = pos[i].id.replace(/^L/,'');
      var hash = location.hash;
      if(e.shiftKey == true && hash.match(/#L\d+(-L\d+)?/)){
        var lines = hash.split('-');
        location.hash = lines[0] + '-L' + line;
      } else {
        var p = $("#L"+line).attr('id',"");
        location.hash = '#L' + line;
        p.attr('id','L'+line);
      }
    }).appendTo(pre);
  }
  var repository = $('.blame-action').data('repository');
  $('.blame-action').click(function(e){
    if(history.pushState && $('pre.prettyprint.no-renderable').length){
      e.preventDefault();
      history.pushState(null, null, this.href);
      updateBlame();
    }
  });

  function updateBlame(){
    var m = /^\/(blame|blob)(\/.*)$/.exec(location.pathname.substring(repository.length));
    var mode = m[1];
    $('.blame-action').toggleClass("active", mode=='blame').attr('href', repository + (m[1]=='blame'?'/blob':'/blame')+m[2]);
    if(pre.parents("td").find(".blame").length){
      pre.parents("div.container").toggleClass("blame-container", mode=='blame');
      updateSourceLineNum();
      return;
    }
    if(mode=='blob'){
      updateSourceLineNum();
      return;
    }
    $(document.body).toggleClass('no-box-shadow',document.body.style.boxShadow===undefined);
    $('.blame-action').addClass("active");
    var base = $('<div class="blame">').css({height:pre.height()}).prependTo(pre.parents("td")[0]);
    base.parents("div.container").addClass("blame-container");
    updateSourceLineNum();
    $.get($('.blame-action').data('url')).done(function(data){
      var blame = data.blame;
      var index = [];
      for(var i=0;i<blame.length;i++){
        for(var j=0;j<blame[i].lines.length;j++){
          index[blame[i].lines[j]]=blame[i];
        }
      }
      var blame, lastDiv, now=new Date().getTime();

      $('pre.prettyprint ol.linenums li').each(function(i, e){
        var p=$(e).position();
        var h=$(e).height();
        if(blame == index[i]){
          lastDiv.css("min-height",(p.top+h+1) - lastDiv.position().top);
        }else{
          $(e).addClass('blame-sep')
          blame = index[i];
          var sha = $('<div class="blame-sha">')
             .append($('<a>').attr("href",data.root+'/commit/'+blame.id).text(blame.id.substr(0,7)));
          if(blame.prev){
             sha.append($('<br />'))
             .append($('<a class="muted-link">').text('prev').attr("href",data.root+'/blame/'+blame.prev+'/'+(blame.prevPath||data.path)));
          }
          lastDiv = $('<div class="blame-info">')
           .addClass('heat'+Math.min(10,Math.max(1,Math.ceil((now-blame.commited)/(24*3600*1000*70)))))
           .toggleClass('blame-last',blame.id==data.last)
           .data('line', (i + 1))
           .css({
             "top" : p.top + 'px',
             "min-height" : h+'px'
           })
           .append(sha)
           .append($(blame.avatar).addClass('avatar').css({"float":"left"}))
           .append($('<div class="blame-commit-title">').text(blame.message))
           .append($('<div class="muted">').html(blame.author+ " authed "+blame.authed))
           .appendTo(base);
        }
      });
    });
    return false;
  };
  updateBlame();
});

/**
 * Hightlight lines which are specified by URL hash.
 */
function updateHighlighting(){
  var hash = location.hash;
  if(hash.match(/#L\d+(-L\d+)?/)){
    $('li.highlight').removeClass('highlight');
    var lines = hash.substr(1).split('-');
    if(lines.length == 1){
      $('#' + lines[0]).addClass('highlight');
      if(!updateHighlighting.scrolling){
        $(window).scrollTop($('#' + lines[0]).offset().top - 40);
      }
    } else if(lines.length > 1){
      var start = parseInt(lines[0].substr(1));
      var end   = parseInt(lines[1].substr(1));
      for(var i = start; i <= end; i++){
        $('#L' + i).addClass('highlight');
      }
      if(!updateHighlighting.scrolling){
        $(window).scrollTop($('#L' + start).offset().top - 40);
      }
    }
    updateHighlighting.scrolling = true;
  }
}
</script>