Changeset - fd92fe65a2ab
[Not reviewed]
default
0 5 0
Mads Kiilerich - 6 years ago 2020-01-10 00:34:22
mads@kiilerich.com
eslint: fix "is already defined"
5 files changed with 23 insertions and 24 deletions:
0 comments (0 inline, 0 general)
kallithea/public/js/base.js
Show inline comments
 
@@ -316,335 +316,333 @@ var pyroutes = (function() {
 
            return result;
 
        },
 
        'register': function(route_name, route_tmpl, req_params) {
 
            if (typeof(req_params) != 'object') {
 
                req_params = [];
 
            }
 
            var keys = [];
 
            for (var i=0; i < req_params.length; i++) {
 
                keys.push(req_params[i]);
 
            }
 
            matchlist[route_name] = [
 
                unescape(route_tmpl),
 
                keys
 
            ]
 
        },
 
        '_routes': function(){
 
            return matchlist;
 
        }
 
    }
 
})();
 

	
 

	
 
/* Invoke all functions in callbacks */
 
var _run_callbacks = function(callbacks){
 
    if (callbacks !== undefined){
 
        var _l = callbacks.length;
 
        for (var i=0;i<_l;i++){
 
            var func = callbacks[i];
 
            if(typeof(func)=='function'){
 
                try{
 
                    func();
 
                }catch (err){}
 
            }
 
        }
 
    }
 
}
 

	
 
/**
 
 * turns objects into GET query string
 
 */
 
function _toQueryString(o) {
 
    if(typeof o !== 'object') {
 
        return false;
 
    }
 
    var _p, _qs = [];
 
    for(_p in o) {
 
        _qs.push(encodeURIComponent(_p) + '=' + encodeURIComponent(o[_p]));
 
    }
 
    return _qs.join('&');
 
}
 

	
 
/**
 
 * Load HTML into DOM using Ajax
 
 *
 
 * @param $target: load html async and place it (or an error message) here
 
 * @param success: success callback function
 
 * @param args: query parameters to pass to url
 
 */
 
function asynchtml(url, $target, success, args){
 
    if(args===undefined){
 
        args=null;
 
    }
 
    $target.html(_TM['Loading ...']).css('opacity','0.3');
 

	
 
    return $.ajax({url: url, data: args, headers: {'X-PARTIAL-XHR': '1'}, cache: false, dataType: 'html'})
 
        .done(function(html) {
 
                $target.html(html);
 
                $target.css('opacity','1.0');
 
                //execute the given original callback
 
                if (success !== undefined && success) {
 
                    success();
 
                }
 
            })
 
        .fail(function(jqXHR, textStatus) {
 
                if (textStatus == "abort")
 
                    return;
 
                $target.html('<span class="bg-danger">ERROR: {0}</span>'.format(textStatus));
 
                $target.css('opacity','1.0');
 
            })
 
        ;
 
}
 

	
 
function ajaxGET(url, success, failure) {
 
    if(failure === undefined) {
 
        failure = function(jqXHR, textStatus) {
 
                if (textStatus != "abort")
 
                    alert("Ajax GET error: " + textStatus);
 
            };
 
    }
 
    return $.ajax({url: url, headers: {'X-PARTIAL-XHR': '1'}, cache: false})
 
        .done(success)
 
        .fail(failure);
 
}
 

	
 
function ajaxPOST(url, postData, success, failure) {
 
    postData['_session_csrf_secret_token'] = _session_csrf_secret_token;
 
    var postData = _toQueryString(postData);
 
    if(failure === undefined) {
 
        failure = function(jqXHR, textStatus) {
 
                if (textStatus != "abort")
 
                    alert("Error posting to server: " + textStatus);
 
            };
 
    }
 
    return $.ajax({url: url, data: postData, type: 'POST', headers: {'X-PARTIAL-XHR': '1'}, cache: false})
 
    return $.ajax({url: url, data: _toQueryString(postData), type: 'POST', headers: {'X-PARTIAL-XHR': '1'}, cache: false})
 
        .done(success)
 
        .fail(failure);
 
}
 

	
 

	
 
/**
 
 * activate .show_more links
 
 * the .show_more must have an id that is the the id of an element to hide prefixed with _
 
 * the parentnode will be displayed
 
 */
 
function show_more_event(){
 
    $('.show_more').click(function(e){
 
        var el = e.currentTarget;
 
        $('#' + el.id.substring(1)).hide();
 
        $(el.parentNode).show();
 
    });
 
}
 

	
 

	
 
function _onSuccessFollow(target){
 
    var $target = $(target);
 
    var $f_cnt = $('#current_followers_count');
 
    if ($target.hasClass('follow')) {
 
        $target.removeClass('follow').addClass('following');
 
        $target.prop('title', _TM['Stop following this repository']);
 
        if ($f_cnt.html()) {
 
            var cnt = Number($f_cnt.html())+1;
 
            const cnt = Number($f_cnt.html())+1;
 
            $f_cnt.html(cnt);
 
        }
 
    } else {
 
        $target.removeClass('following').addClass('follow');
 
        $target.prop('title', _TM['Start following this repository']);
 
        if ($f_cnt.html()) {
 
            var cnt = Number($f_cnt.html())-1;
 
            const cnt = Number($f_cnt.html())-1;
 
            $f_cnt.html(cnt);
 
        }
 
    }
 
}
 

	
 
function toggleFollowingRepo(target, follows_repository_id){
 
    var args = {
 
        'follows_repository_id': follows_repository_id,
 
        '_session_csrf_secret_token': _session_csrf_secret_token
 
    }
 
    $.post(TOGGLE_FOLLOW_URL, args, function(){
 
            _onSuccessFollow(target);
 
        });
 
    return false;
 
}
 

	
 
function showRepoSize(target, repo_name){
 
    var args = '_session_csrf_secret_token=' + _session_csrf_secret_token;
 

	
 
    if(!$("#" + target).hasClass('loaded')){
 
        $("#" + target).html(_TM['Loading ...']);
 
        var url = pyroutes.url('repo_size', {"repo_name":repo_name});
 
        $.post(url, args, function(data) {
 
            $("#" + target).html(data);
 
            $("#" + target).addClass('loaded');
 
        });
 
    }
 
    return false;
 
}
 

	
 
/**
 
 * load tooltips dynamically based on data attributes, used for .lazy-cs changeset links
 
 */
 
function get_changeset_tooltip() {
 
    var $target = $(this);
 
    var tooltip = $target.data('tooltip');
 
    if (!tooltip) {
 
        var raw_id = $target.data('raw_id');
 
        var repo_name = $target.data('repo_name');
 
        var url = pyroutes.url('changeset_info', {"repo_name": repo_name, "revision": raw_id});
 

	
 
        $.ajax(url, {
 
            async: false,
 
            success: function(data) {
 
                tooltip = data["message"];
 
            }
 
        });
 
        $target.data('tooltip', tooltip);
 
    }
 
    return tooltip;
 
}
 

	
 
/**
 
 * activate tooltips and popups
 
 */
 
function tooltip_activate(){
 
    function placement(p, e){
 
        if(e.getBoundingClientRect().top > 2*$(window).height()/3){
 
            return 'top';
 
        }else{
 
            return 'bottom';
 
        }
 
    }
 
    $(document).ready(function(){
 
        $('[data-toggle="tooltip"]').tooltip({
 
            container: 'body',
 
            placement: placement
 
        });
 
        $('[data-toggle="popover"]').popover({
 
            html: true,
 
            container: 'body',
 
            placement: placement,
 
            trigger: 'hover',
 
            template: '<div class="popover cs-popover" role="tooltip"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'
 
        });
 
        $('.lazy-cs').tooltip({
 
            title: get_changeset_tooltip,
 
            placement: placement
 
        });
 
    });
 
}
 

	
 

	
 
/**
 
 * Quick filter widget
 
 *
 
 * @param target: filter input target
 
 * @param nodes: list of nodes in html we want to filter.
 
 * @param display_element function that takes current node from nodes and
 
 *    does hide or show based on the node
 
 */
 
var q_filter = (function() {
 
    var _namespace = {};
 
    var namespace = function (target) {
 
        if (!(target in _namespace)) {
 
            _namespace[target] = {};
 
        }
 
        return _namespace[target];
 
    };
 
    return function (target, $nodes, display_element) {
 
        var $nodes = $nodes;
 
        var $q_filter_field = $('#' + target);
 
        var F = namespace(target);
 

	
 
        $q_filter_field.keyup(function () {
 
            clearTimeout(F.filterTimeout);
 
            F.filterTimeout = setTimeout(F.updateFilter, 600);
 
        });
 

	
 
        F.filterTimeout = null;
 

	
 
        F.updateFilter = function () {
 
            // Reset timeout
 
            F.filterTimeout = null;
 

	
 
            var obsolete = [];
 

	
 
            var req = $q_filter_field.val().toLowerCase();
 

	
 
            var showing = 0;
 
            $nodes.each(function () {
 
                var n = this;
 
                var target_element = display_element(n);
 
                if (req && n.innerHTML.toLowerCase().indexOf(req) == -1) {
 
                    $(target_element).hide();
 
                }
 
                else {
 
                    $(target_element).show();
 
                    showing += 1;
 
                }
 
            });
 

	
 
            $('#repo_count').html(showing);
 
            /* FIXME: don't hardcode */
 
        }
 
    }
 
})();
 

	
 

	
 
/**
 
 * Comment handling
 
 */
 

	
 
// move comments to their right location, inside new trs
 
function move_comments($anchorcomments) {
 
    $anchorcomments.each(function(i, anchorcomment) {
 
        var $anchorcomment = $(anchorcomment);
 
        var target_id = $anchorcomment.data('target-id');
 
        var $comment_div = _get_add_comment_div(target_id);
 
        var f_path = $anchorcomment.data('f_path');
 
        var line_no = $anchorcomment.data('line_no');
 
        if ($comment_div[0]) {
 
            $comment_div.append($anchorcomment.children());
 
            if (f_path && line_no) {
 
                _comment_div_append_add($comment_div, f_path, line_no);
 
            } else {
 
                _comment_div_append_form($comment_div, f_path, line_no);
 
            }
 
        } else {
 
            $anchorcomment.before("<span class='bg-warning'>Comment to {0} line {1} which is outside the diff context:</span>".format(f_path || '?', line_no || '?'));
 
        }
 
    });
 
    linkInlineComments($('.firstlink'), $('.comment:first-child'));
 
}
 

	
 
// comment bubble was clicked - insert new tr and show form
 
function show_comment_form($bubble) {
 
    var children = $bubble.closest('tr.line').children('[id]');
 
    var line_td_id = children[children.length - 1].id;
 
    var $comment_div = _get_add_comment_div(line_td_id);
 
    var f_path = $bubble.closest('[data-f_path]').data('f_path');
 
    var parts = line_td_id.split('_');
 
    var line_no = parts[parts.length-1];
 
    comment_div_state($comment_div, f_path, line_no, true);
 
}
 

	
 
// return comment div for target_id - add it if it doesn't exist yet
 
function _get_add_comment_div(target_id) {
 
    var comments_box_id = 'comments-' + target_id;
 
    var $comments_box = $('#' + comments_box_id);
 
    if (!$comments_box.length) {
 
        var html = '<tr><td id="{0}" colspan="3" class="inline-comments"></td></tr>'.format(comments_box_id);
 
        $('#' + target_id).closest('tr').after(html);
 
        $comments_box = $('#' + comments_box_id);
 
    }
 
    return $comments_box;
 
}
 

	
 
// Set $comment_div state - showing or not showing form and Add button.
 
// An Add button is shown on non-empty forms when no form is shown.
 
// The form is controlled by show_form_opt - if undefined, form is only shown for general comments.
 
function comment_div_state($comment_div, f_path, line_no, show_form_opt) {
 
    var show_form = show_form_opt !== undefined ? show_form_opt : !f_path && !line_no;
 
    var $forms = $comment_div.children('.comment-inline-form');
 
    var $buttonrow = $comment_div.children('.add-button-row');
 
    var $comments = $comment_div.children('.comment:not(.submitting)');
 
    $forms.remove();
kallithea/public/js/codemirror_loadmode.js
Show inline comments
 
'use strict';
 

	
 
(function() {
 
  var loading = {};
 
  function splitCallback(cont, n) {
 
    var countDown = n;
 
    return function() { if (--countDown == 0) cont(); };
 
  }
 
  function ensureDeps(mode, cont) {
 
    var deps = CodeMirror.modes[mode].dependencies;
 
    if (!deps) return cont();
 
    var missing = [];
 
    for (var i = 0; i < deps.length; ++i) {
 
    for (let i = 0; i < deps.length; ++i) {
 
      if (!CodeMirror.modes.hasOwnProperty(deps[i]))
 
        missing.push(deps[i]);
 
    }
 
    if (!missing.length) return cont();
 
    var split = splitCallback(cont, missing.length);
 
    for (var i = 0; i < missing.length; ++i)
 
    for (let i = 0; i < missing.length; ++i)
 
      CodeMirror.requireMode(missing[i], split);
 
  }
 

	
 
  CodeMirror.requireMode = function(mode, cont) {
 
    if (typeof mode != "string") mode = mode.mode;
 
    if (CodeMirror.modes.hasOwnProperty(mode)) return ensureDeps(mode, cont);
 
    if (loading.hasOwnProperty(mode)) return loading[mode].push(cont);
 

	
 
    var script = document.createElement("script");
 
    script.src = CodeMirror.modeURL.replace(/%N/g, mode);
 
    var others = document.getElementsByTagName("script")[0];
 
    others.parentNode.insertBefore(script, others);
 
    var list = loading[mode] = [cont];
 
    var count = 0, poll = setInterval(function() {
 
      if (++count > 100) return clearInterval(poll);
 
      if (CodeMirror.modes.hasOwnProperty(mode)) {
 
        clearInterval(poll);
 
        loading[mode] = null;
 
        ensureDeps(mode, function() {
 
          for (var i = 0; i < list.length; ++i) list[i]();
 
        });
 
      }
 
    }, 200);
 
  };
 

	
 
  CodeMirror.autoLoadMode = function(instance, mode) {
 
    if (!CodeMirror.modes.hasOwnProperty(mode))
 
      CodeMirror.requireMode(mode, function() {
 
        instance.setOption("mode", instance.getOption("mode"));
 
      });
 
    instance.setOption("mode", mode.mime);
 
  };
 

	
 
  CodeMirror.findExtensionByMode = function(modeInfo) {
 
    if (modeInfo.ext) {
 
      return modeInfo.ext[0];
 
    } else if (modeInfo.mode) {
 
      return modeInfo.mode;
 
    } else {
 
      return "txt";
 
    }
 
  };
 

	
 
  CodeMirror.getFilenameAndExt = function(filename){
 
    var parts = filename.split('.');
 
    var ext;
 

	
 
    if (parts.length > 1){
 
        var ext = parts.pop();
 
        var filename = parts.join("");
 
        ext = parts.pop();
 
        filename = parts.join("");
 
    }
 
    return {"filename": filename, "ext": ext};
 
  };
 

	
 
}());
 

	
 

	
 
//overlay plugin
 

	
 
// Utility function that allows modes to be combined. The mode given
 
// as the base argument takes care of most of the normal mode
 
// functionality, but a second (typically simple) mode is used, which
 
// can override the style of text. Both modes get to parse all of the
 
// text, but when both assign a non-null style to a piece of code, the
 
// overlay wins, unless the combine argument was true, in which case
 
// the styles are combined.
 

	
 
// overlayParser is the old, deprecated name
 
CodeMirror.overlayMode = CodeMirror.overlayParser = function(base, overlay, combine) {
 
  return {
 
    startState: function() {
 
      return {
 
        base: CodeMirror.startState(base),
 
        overlay: CodeMirror.startState(overlay),
 
        basePos: 0, baseCur: null,
 
        overlayPos: 0, overlayCur: null
 
      };
 
    },
 
    copyState: function(state) {
 
      return {
 
        base: CodeMirror.copyState(base, state.base),
 
        overlay: CodeMirror.copyState(overlay, state.overlay),
 
        basePos: state.basePos, baseCur: null,
 
        overlayPos: state.overlayPos, overlayCur: null
 
      };
 
    },
 

	
 
    token: function(stream, state) {
 
      if (stream.start == state.basePos) {
 
        state.baseCur = base.token(stream, state.base);
 
        state.basePos = stream.pos;
 
      }
 
      if (stream.start == state.overlayPos) {
 
        stream.pos = stream.start;
 
        state.overlayCur = overlay.token(stream, state.overlay);
 
        state.overlayPos = stream.pos;
 
      }
 
      stream.pos = Math.min(state.basePos, state.overlayPos);
 
      if (stream.eol()) state.basePos = state.overlayPos = 0;
 

	
 
      if (state.overlayCur == null) return state.baseCur;
 
      if (state.baseCur != null && combine) return state.baseCur + " " + state.overlayCur;
 
      else return state.overlayCur;
 
    },
 

	
 
    indent: base.indent && function(state, textAfter) {
 
      return base.indent(state.base, textAfter);
 
    },
 
    electricChars: base.electricChars,
 

	
 
    innerMode: function(state) { return {state: state.base, mode: base}; },
 

	
 
    blankLine: function(state) {
 
      if (base.blankLine) base.blankLine(state.base);
 
      if (overlay.blankLine) overlay.blankLine(state.overlay);
 
    }
 
  };
 
};
kallithea/public/js/graph.js
Show inline comments
 
'use strict';
 

	
 
// branch_renderer.js - Rendering of branch DAGs on the client side
 
//
 
// Copyright 2010 Marcin Kuzminski <marcin AT python-works DOT com>
 
// Copyright 2008 Jesper Noehr <jesper AT noehr DOT org>
 
// Copyright 2008 Dirkjan Ochtman <dirkjan AT ochtman DOT nl>
 
// Copyright 2006 Alexander Schremmer <alex AT alexanderweb DOT de>
 
//
 
// derived from code written by Scott James Remnant <scott@ubuntu.com>
 
// Copyright 2005 Canonical Ltd.
 
//
 
// This software may be used and distributed according to the terms
 
// of the GNU General Public License, incorporated herein by reference.
 

	
 
var colors = [
 
	[ 1.0, 0.0, 0.0 ],
 
	[ 1.0, 1.0, 0.0 ],
 
	[ 0.0, 1.0, 0.0 ],
 
	[ 0.0, 1.0, 1.0 ],
 
	[ 0.0, 0.0, 1.0 ],
 
	[ 1.0, 0.0, 1.0 ],
 
	[ 1.0, 1.0, 0.0 ],
 
	[ 0.0, 0.0, 0.0 ]
 
];
 

	
 
function BranchRenderer(canvas_id, content_id, row_id_prefix) {
 
	// canvas_id is canvas to render into
 
	// content_id's height is applied to canvas
 
	// row_id_prefix is prefix that is applied to get row id's
 
	this.canvas = document.getElementById(canvas_id);
 
	var content = document.getElementById(content_id);
 

	
 
	if (!document.createElement("canvas").getContext)
 
		this.canvas = window.G_vmlCanvasManager.initElement(this.canvas);
 
	if (!this.canvas) { // canvas creation did for some reason fail - fail silently
 
		this.render = function() {};
 
		return;
 
	}
 
	this.ctx = this.canvas.getContext('2d');
 
	this.ctx.strokeStyle = 'rgb(0, 0, 0)';
 
	this.ctx.fillStyle = 'rgb(0, 0, 0)';
 
	this.cur = [0, 0];
 
	this.line_width = 2.0;
 
	this.dot_radius = 3.5;
 
	this.close_x = 1.5 * this.dot_radius;
 
	this.close_y = 0.5 * this.dot_radius;
 

	
 
	this.calcColor = function(color, bg, fg) {
 
		color %= colors.length;
 
		var red = (colors[color][0] * fg) || bg;
 
		var green = (colors[color][1] * fg) || bg;
 
		var blue = (colors[color][2] * fg) || bg;
 
		red = Math.round(red * 255);
 
		green = Math.round(green * 255);
 
		blue = Math.round(blue * 255);
 
		var s = 'rgb(' + red + ', ' + green + ', ' + blue + ')';
 
		return s;
 
	}
 

	
 
	this.setColor = function(color, bg, fg) {
 
		var s = this.calcColor(color, bg, fg);
 
		this.ctx.strokeStyle = s;
 
		this.ctx.fillStyle = s;
 
	}
 

	
 
	this.render = function(data) {
 
		var idx = 1;
 
		var canvasWidth = $(this.canvas).parent().width();
 

	
 
		this.canvas.setAttribute('width',canvasWidth);
 
		this.canvas.setAttribute('height',content.clientHeight);
 

	
 
		// HiDPI version needs to be scaled by 2x then halved via css
 
		// Note: Firefox on OS X fails scaling if the canvas height is more than 32k
 
		if (window.devicePixelRatio && content.clientHeight * window.devicePixelRatio < 32768) {
 
			this.canvas.setAttribute('width', canvasWidth * window.devicePixelRatio);
 
			this.canvas.setAttribute('height', content.clientHeight * window.devicePixelRatio);
 
			this.canvas.style.width = canvasWidth + "px";
 
			this.canvas.style.height = content.clientHeight + "px";
 
			this.ctx.scale(window.devicePixelRatio, window.devicePixelRatio);
 
		}
 

	
 
		var lineCount = 1;
 
		for (var i=0;i<data.length;i++) {
 
		for (let i=0;i<data.length;i++) {
 
			var in_l = data[i][1];
 
			for (var j in in_l) {
 
				var m = in_l[j][0];
 
				if (m > lineCount)
 
					lineCount = m;
 
			}
 
		}
 

	
 
		var edge_pad = this.dot_radius + 2;
 
		var box_size = Math.min(18, (canvasWidth - edge_pad * 2) / lineCount);
 
		var base_x = canvasWidth - edge_pad;
 

	
 
		for (var i=0; i < data.length; ++i) {
 
		for (let i=0; i < data.length; ++i) {
 
			var row = document.getElementById(row_id_prefix+idx);
 
			if (row == null) {
 
				console.log("error: row "+row_id_prefix+idx+" not found");
 
				continue;
 
			}
 
			var next = document.getElementById(row_id_prefix+(idx+1));
 
			var extra = 0;
 

	
 
			const cur = data[i];
 
			const node = cur[0];
 
			const in_l = cur[1];
 
			const closing = cur[2];
 
			const obsolete_node = cur[3];
 
			const bumped_node = cur[4];
 
			const divergent_node = cur[5];
 
			const extinct_node = cur[6];
 
			const unstable_node = cur[7];
 

	
 
			// center dots on the first element in a td (not necessarily the first one, but there must be one)
 
			var firstincell = $(row).find('td>*:visible')[0];
 
			var nextFirstincell = $(next).find('td>*:visible')[0];
 
			var rowY = Math.floor(row.offsetTop + firstincell.offsetTop + firstincell.offsetHeight/2);
 
			var nextY = Math.floor((next == null) ? rowY + row.offsetHeight/2 : next.offsetTop + nextFirstincell.offsetTop + nextFirstincell.offsetHeight/2);
 

	
 
			for (var j in in_l) {
 
			for (let j in in_l) {
 
				const line = in_l[j];
 
				const start = line[0];
 
				const end = line[1];
 
				const color = line[2];
 
				const obsolete_line = line[3];
 

	
 
				const x = Math.floor(base_x - box_size * start);
 

	
 
				// figure out if this is a dead-end;
 
				// we want to fade away this line
 
				var dead_end = true;
 
				if (next != null) {
 
					const nextdata = data[i+1];
 
					const next_l = nextdata[1];
 
					for (var k=0; k < next_l.length; ++k) {
 
						if (next_l[k][0] == end) {
 
							dead_end = false;
 
							break;
 
						}
 
					}
 
					if (nextdata[0][0] == end) // this is a root - not a dead end
 
						dead_end = false;
 
				}
 

	
 
				if (dead_end) {
 
					var gradient = this.ctx.createLinearGradient(x,rowY,x,nextY);
 
					let gradient = this.ctx.createLinearGradient(x,rowY,x,nextY);
 
					gradient.addColorStop(0,this.calcColor(color, 0.0, 0.65));
 
					gradient.addColorStop(1,this.calcColor(color, 1.0, 0.0));
 
					this.ctx.strokeStyle = gradient;
 
					this.ctx.fillStyle = gradient;
 
				}
 
				// if this is a merge of differently
 
				// colored line, make it a gradient towards
 
				// the merged color
 
				else if (color != node[1] && start == node[0])
 
				{
 
					var gradient = this.ctx.createLinearGradient(x,rowY,x,nextY);
 
					let gradient = this.ctx.createLinearGradient(x,rowY,x,nextY);
 
					gradient.addColorStop(0,this.calcColor(node[1], 0.0, 0.65));
 
					gradient.addColorStop(1,this.calcColor(color, 0.0, 0.65));
 
					this.ctx.strokeStyle = gradient;
 
					this.ctx.fillStyle = gradient;
 
				}
 
				else
 
				{
 
					this.setColor(color, 0.0, 0.65);
 
				}
 

	
 
				this.ctx.lineWidth=this.line_width;
 
				this.ctx.beginPath();
 
				if (obsolete_line)
 
				{
 
					this.ctx.setLineDash([5]);
 
				}
 
				this.ctx.beginPath();
 
				this.ctx.moveTo(x, rowY);
 
				if (start == end)
 
				{
 
					this.ctx.lineTo(x,nextY+extra,3);
 
				}
 
				else
 
				{
 
					var x2 = Math.floor(base_x - box_size * end);
 
					var ymid = (rowY+nextY) / 2;
 
					if (obsolete_node)
 
					{
 
						this.ctx.setLineDash([5]);
 
					}
 
					this.ctx.bezierCurveTo (x,ymid,x2,ymid,x2,nextY);
 
				}
 
				this.ctx.stroke();
 
				this.ctx.setLineDash([]); // reset the dashed line, if any
 
			}
 

	
 
			const column = node[0];
 
			const color = node[1];
 

	
 
			const x = Math.floor(base_x - box_size * column);
 

	
 
			this.setColor(color, 0.25, 0.75);
 
			if(unstable_node)
 
			{
 
				this.ctx.fillStyle = 'rgb(255, 0, 0)';
 
			}
 

	
 
			let r = this.dot_radius
 
			if (obsolete_node)
 
			{
 
				this.ctx.beginPath();
 
				this.ctx.moveTo(x - this.close_x, rowY - this.close_y - 3);
 
				this.ctx.lineTo(x - this.close_x + 2*this.close_x, rowY - this.close_y + 4*this.close_y - 1);
 
				this.ctx.moveTo(x - this.close_x, rowY - this.close_y + 4*this.close_y - 1);
 
				this.ctx.lineTo(x - this.close_x + 2*this.close_x, rowY - this.close_y - 3);
 
				this.ctx.stroke();
 
				r -= 0.5
 
			}
 
			if (closing)
 
			{
 
				this.ctx.fillRect(x - this.close_x, rowY - this.close_y, 2*this.close_x, 2*this.close_y);
 
			}
 
			else
 
			{
 
				this.ctx.beginPath();
 
				this.ctx.arc(x, rowY, r, 0, Math.PI * 2, true);
 
				this.ctx.fill();
 
			}
 

	
 
			idx++;
 
		}
 

	
 
	}
 

	
 
}
kallithea/templates/summary/statistics.html
Show inline comments
 
<%inherit file="/base/base.html"/>
 

	
 
<%block name="title">
 
    ${_('%s Statistics') % c.repo_name}
 
</%block>
 

	
 
<%def name="breadcrumbs_links()">
 
    ${_('Statistics')}
 
</%def>
 

	
 
<%block name="header_menu">
 
    ${self.menu('repositories')}
 
</%block>
 

	
 
<%block name="head_extra">
 
  <link href="${h.url('atom_feed_home',repo_name=c.db_repo.repo_name,api_key=request.authuser.api_key)}" rel="alternate" title="${_('%s ATOM feed') % c.repo_name}" type="application/atom+xml" />
 
  <link href="${h.url('rss_feed_home',repo_name=c.db_repo.repo_name,api_key=request.authuser.api_key)}" rel="alternate" title="${_('%s RSS feed') % c.repo_name}" type="application/rss+xml" />
 
  <script src="${h.url('/js/jquery.flot.js', ver=c.kallithea_version)}"></script>
 
  <script src="${h.url('/js/jquery.flot.selection.js', ver=c.kallithea_version)}"></script>
 
  <script src="${h.url('/js/jquery.flot.time.js', ver=c.kallithea_version)}"></script>
 
</%block>
 

	
 
<%def name="main()">
 
${self.repo_context_bar('summary')}
 
    <div class="panel panel-primary">
 
    <div class="panel-heading clearfix">
 
        ${self.breadcrumbs()}
 
    </div>
 

	
 
    <div class="graph panel-body">
 
        <div>
 
        %if not c.stats_percentage:
 
           ${c.no_data_msg}
 
           %if h.HasPermissionAny('hg.admin')('enable stats on from summary'):
 
                ${h.link_to(_('Enable'),h.url('edit_repo',repo_name=c.repo_name),class_="btn btn-default btn-xs")}
 
           %endif
 
        %else:
 
            ${_('Stats gathered: ')} ${c.stats_percentage}%
 
        %endif
 
        </div>
 
        <div id="commit_history" class="pull-left"></div>
 

	
 
        <div id="legend_data" class="pull-left">
 
            <div id="legend_container"></div>
 
            <div id="legend_choices">
 
                <table class="table" id="legend_choices_tables"></table>
 
            </div>
 
        </div>
 

	
 
        <div id="overview"></div>
 
    </div>
 
</div>
 

	
 
<script>'use strict';
 
var data = ${h.js(c.trending_languages)};
 
var total = 0;
 
var tbl = document.createElement('table');
 
tbl.setAttribute('class','trending_language_tbl');
 
var cnt = 0;
 
for (var i=0;i<data.length;i++){
 
for (let i=0;i<data.length;i++){
 
    total+= data[i][1].count;
 
}
 
for (var i=0;i<data.length;i++){
 
for (let i=0;i<data.length;i++){
 
    cnt += 1;
 

	
 
    var hide = cnt>2;
 
    var tr = document.createElement('tr');
 
    if (hide){
 
        tr.setAttribute('style','display:none');
 
        tr.setAttribute('class','stats_hidden');
 
    }
 
    var k = data[i][0];
 
    var obj = data[i][1];
 
    var percentage = Math.round((obj.count/total*100),2);
 

	
 
    var td1 = document.createElement('td');
 
    td1.width = 150;
 
    var trending_language_label = document.createElement('div');
 
    trending_language_label.innerHTML = obj.desc+" ("+k+")";
 
    td1.appendChild(trending_language_label);
 

	
 
    var td2 = document.createElement('td');
 
    td2.setAttribute('style','padding-right:14px !important');
 
    var trending_language = document.createElement('div');
 
    var nr_files = obj.count + ' ' + ${h.jshtml(_('files'))};
 

	
 
    trending_language.title = k+" "+nr_files;
 

	
 
    if (percentage>22){
 
        trending_language.innerHTML = "<b style='font-size:0.8em'>"+percentage+"% "+nr_files+ "</b>";
 
    }
 
    else{
 
        trending_language.innerHTML = "<b style='font-size:0.8em'>"+percentage+"%</b>";
 
    }
 

	
 
    trending_language.setAttribute("class", 'trending_language top-right-rounded-corner bottom-right-rounded-corner');
 
    trending_language.style.width=percentage+"%";
 
    td2.appendChild(trending_language);
 

	
 
    tr.appendChild(td1);
 
    tr.appendChild(td2);
 
    tbl.appendChild(tr);
 
    if(cnt == 3){
 
        var show_more = document.createElement('tr');
 
        var td = document.createElement('td');
 
        let lnk = document.createElement('a');
 

	
 
        lnk.href='#';
 
        lnk.innerHTML = ${h.jshtml(_('Show more'))};
 
        lnk.id='code_stats_show_more';
 
        td.appendChild(lnk);
 

	
 
        show_more.appendChild(td);
 
        show_more.appendChild(document.createElement('td'));
 
        tbl.appendChild(show_more);
 
    }
 

	
 
}
 

	
 
</script>
 
<script>'use strict';
 

	
 
/**
 
 * Plots summary graph
 
 *
 
 * @class SummaryPlot
 
 * @param {from} initial from for detailed graph
 
 * @param {to} initial to for detailed graph
 
 * @param {dataset}
 
 * @param {overview_dataset}
 
 */
 
function SummaryPlot(from,to,dataset,overview_dataset) {
 
    var initial_ranges = {
 
        "xaxis":{
 
            "from":from,
 
            "to":to
 
        }
 
    };
 
    for(var key in dataset){
 
      var data = dataset[key].data;
 
    for(let key in dataset){
 
      let data = dataset[key].data;
 
      for(var d in data){
 
        data[d].time *= 1000;
 
      }
 
    }
 
    for(var key in overview_dataset){
 
    for(let key in overview_dataset){
 
      overview_dataset[key][0] *= 1000;
 
    }
 
    var choiceContainer = $("#legend_choices")[0];
 
    var choiceContainerTable = $("#legend_choices_tables")[0];
 
    var $plotContainer = $('#commit_history');
 
    var plotContainer = $('#commit_history')[0];
 
    var $overviewContainer = $('#overview');
 
    var overviewContainer = $('#overview')[0];
 

	
 
    var plot_options = {
 
        bars: {show:true, align: 'center', lineWidth: 4},
 
        legend: {show:true,
 
                container: "#legend_container",
 
                labelFormatter: function(label) {
 
                        return '<a href="javascript:void(0)"> ' + label + '</a>';
 
                    }
 
        },
 
        points: {show:true, radius: 0, fill: false},
 
        yaxis: {tickDecimals: 0},
 
        xaxis: {
 
            mode: "time",
 
            timeformat: "%d/%m",
 
            min: from,
 
            max: to
 
        },
 
        grid: {
 
            hoverable: true,
 
            clickable: true,
 
            autoHighlight: true,
 
            color: "#999"
 
        },
 
        //selection: {mode: "x"}
 
    };
 
    var overview_options = {
 
        legend:{show:false},
 
        bars: {show:true, barWidth: 2},
 
        shadowSize: 0,
 
        xaxis: {mode: "time", timeformat: "%d/%m/%y"},
 
        yaxis: {ticks: 3, min: 0, tickDecimals:0},
 
        grid: {color: "#999"},
 
        selection: {mode: "x"}
 
    };
 

	
 
    /**
 
    *get dummy data needed in few places
 
    */
 
    function getDummyData(label){
 
        return {"label":label,
 
         "data":[{"time":0,
 
             "commits":0,
 
                 "added":0,
 
                 "changed":0,
 
                 "removed":0
 
            }],
 
            "schema":["commits"],
 
            "color":'#ffffff'
 
        }
 
    }
 

	
 
    /**
 
     * generate checkboxes accordingly to data
 
     */
 
    function generateCheckboxes(data) {
 
        //append checkboxes
 
        var i = 0;
 
        choiceContainerTable.innerHTML = '';
 
        for(var pos in data) {
 

	
 
            data[pos].color = i;
 
            i++;
 
            if(data[pos].label != ''){
 
                choiceContainerTable.innerHTML +=
 
                    '<tr style="display:none"><td><label><input type="checkbox" id="id_user_{0}" name="{0}" checked="checked" /> \
 
                     {0}</label></td></tr>'.format(data[pos].label);
 
            }
 
        }
 
    }
 

	
 
    /**
 
     * ToolTip show
 
     */
 
    function showTooltip(x, y, contents) {
 
        var div=document.getElementById('tooltip');
 
        if(!div) {
 
            div = document.createElement('div');
 
            div.id="tooltip";
 
            div.style.position="absolute";
 
            div.style.border='1px solid #fdd';
 
            div.style.padding='2px';
 
            div.style.backgroundColor='#fee';
 
            document.body.appendChild(div);
 
        }
 
        $(div).css('opacity', 0)
 
        div.innerHTML = contents;
 
        div.style.top=(y + 5) + "px";
 
        div.style.left=(x + 5) + "px";
 
@@ -284,173 +284,173 @@ function SummaryPlot(from,to,dataset,ove
 
    /**
 
    * redraw using new checkbox data
 
    */
 
    function plotchoiced(e){
 
        let args = e.data;
 
        var cur_data = args[0];
 
        var cur_ranges = args[1];
 

	
 
        var new_data = [];
 
        var inputs = choiceContainer.getElementsByTagName("input");
 
        inputs[$(e.target).parents('tr').index()].click();
 

	
 
        //show only checked labels
 
        for(var i=0; i<inputs.length; i++) {
 
            var checkbox_key = inputs[i].name;
 

	
 
            if(inputs[i].checked){
 
                for(var d in cur_data){
 
                    if(cur_data[d].label == checkbox_key){
 
                        new_data.push(cur_data[d]);
 
                    }
 
                }
 
            }
 
            else{
 
                //push dummy data to not hide the label
 
                new_data.push(getDummyData(checkbox_key));
 
            }
 
        }
 

	
 
        var new_options = $.extend(plot_options, {
 
            xaxis: {
 
                min: cur_ranges.xaxis.from,
 
                max: cur_ranges.xaxis.to,
 
                mode: "time",
 
                timeformat: "%d/%m"
 
            }
 
        });
 
        if (!new_data){
 
            new_data = [[0,1]];
 
        }
 
        // do the zooming
 
       plot = $.plot(plotContainer, new_data, new_options);
 

	
 
       $plotContainer.on("plotselected", plotselected);
 

	
 
       //resubscribe plothover
 
       $plotContainer.on("plothover", plothover);
 

	
 
       //resubscribe this function after plot update
 
       $('#legend_container tr a').on("click", [cur_data, cur_ranges], plotchoiced);
 

	
 
       // don't fire event on the overview to prevent eternal loop
 
       overview.setSelection(cur_ranges, true);
 

	
 
    }
 

	
 
    /**
 
     * plot only selected items from overview
 
     * @param ranges
 
     * @returns
 
     */
 
    function plotselected(e, ranges) {
 
        //updates the data for new plot
 
        var data = getDataAccordingToRanges(ranges);
 
        generateCheckboxes(data);
 

	
 
        var new_options = $.extend(plot_options, {
 
            xaxis: {
 
                min: ranges.xaxis.from,
 
                max: ranges.xaxis.to,
 
                mode:"time",
 
                timeformat: "%d/%m"
 
            }
 
        });
 
        // do the zooming
 
        plot = $.plot(plotContainer, data, new_options);
 

	
 
        $plotContainer.on("plotselected", plotselected);
 

	
 
        //resubscribe plothover
 
        $plotContainer.on("plothover", plothover);
 

	
 
        // don't fire event on the overview to prevent eternal loop
 
        overview.setSelection(ranges, true);
 

	
 
        //resubscribe choiced
 
        $('#legend_container tr a').on("click", [data, ranges], plotchoiced);
 
    }
 

	
 
    var previousPoint = null;
 

	
 
    function plothover(e, pos, item) {
 
        if (item) {
 
            if (previousPoint != item.datapoint) {
 
                previousPoint = item.datapoint;
 

	
 
                var tooltip = $("#tooltip")[0];
 
                let tooltip = $("#tooltip")[0];
 
                if(tooltip) {
 
                      tooltip.parentNode.removeChild(tooltip);
 
                }
 

	
 
                var d = new Date(item.datapoint[0]);
 
                var fd = d.toDateString();
 
                var nr_commits = item.datapoint[1];
 

	
 
                if (!item.series.label){
 
                    item.series.label = 'commits';
 
                }
 

	
 
                var cur_data = dataset[item.series.label].data[item.dataIndex];
 
                var added = cur_data.added;
 
                var changed = cur_data.changed;
 
                var removed = cur_data.removed;
 

	
 
                var nr_commits_suffix = ' ' + ${h.jshtml(_('commits'))} + ' ';
 
                var added_suffix = ' ' + ${h.jshtml(_('files added'))} + ' ';
 
                var changed_suffix = ' ' + ${h.jshtml(_('files changed'))} + ' ';
 
                var removed_suffix = ' ' + ${h.jshtml(_('files removed'))} + ' ';
 

	
 
                if(nr_commits == 1){ nr_commits_suffix = ' ' + ${h.jshtml(_('commit'))} + ' '; }
 
                if(added == 1) { added_suffix=' ' + ${h.jshtml(_('file added'))} + ' '; }
 
                if(changed == 1) { changed_suffix=' ' + ${h.jshtml(_('file changed'))} + ' '; }
 
                if(removed == 1) { removed_suffix=' ' + ${h.jshtml(_('file removed'))} + ' '; }
 

	
 
                showTooltip(item.pageX, item.pageY, item.series.label + " on " + fd
 
                         +'<br/>'+
 
                         nr_commits + nr_commits_suffix+'<br/>'+
 
                         added + added_suffix +'<br/>'+
 
                         changed + changed_suffix + '<br/>'+
 
                         removed + removed_suffix + '<br/>');
 
            }
 
        }
 
        else {
 
              var tooltip = $("#tooltip")[0];
 
              let tooltip = $("#tooltip")[0];
 

	
 
              if(tooltip) {
 
                    tooltip.parentNode.removeChild(tooltip);
 
              }
 
              previousPoint = null;
 
        }
 
    }
 

	
 
    /**
 
     * MAIN EXECUTION
 
     */
 

	
 
    var data = getDataAccordingToRanges(initial_ranges);
 
    let data = getDataAccordingToRanges(initial_ranges);
 
    generateCheckboxes(data);
 

	
 
    //main plot
 
    var plot = $.plot(plotContainer,data,plot_options);
 

	
 
    //overview
 
    var overview = $.plot(overviewContainer, [overview_dataset], overview_options);
 

	
 
    //show initial selection on overview
 
    overview.setSelection(initial_ranges);
 

	
 
    $plotContainer.on("plotselected", plotselected);
 
    $plotContainer.on("plothover", plothover);
 

	
 
    $overviewContainer.on("plotselected", function (e, ranges) {
 
        plot.setSelection(ranges);
 
    });
 

	
 
    // user choices on overview
 
    $('#legend_container tr a').on("click", [data, initial_ranges], plotchoiced);
 
}
 

	
 
SummaryPlot(${h.js(c.ts_min)}, ${h.js(c.ts_max)}, ${h.js(c.commit_data)}, ${h.js(c.overview_data)});
 
</script>
 

	
 
</%def>
kallithea/templates/summary/summary.html
Show inline comments
 
@@ -248,175 +248,175 @@ $(document).ready(function(){
 
            $(this).addClass('selected');
 
            $(this).select();
 
        }
 
    });
 

	
 
    var $clone_url = $('#clone-url');
 
    var $clone_by_name = $('#clone_by_name');
 
    var $clone_by_id = $('#clone_by_id');
 
    var $clone_ssh = $('#clone_ssh');
 
    $clone_url.on('click', '.btn.use-name', function(){
 
        $clone_by_name.show();
 
        $clone_by_id.hide();
 
        $clone_ssh.hide();
 
    });
 
    $clone_url.on('click', '.btn.use-id', function(){
 
        $clone_by_id.show();
 
        $clone_by_name.hide();
 
        $clone_ssh.hide();
 
    });
 
    $clone_url.on('click', '.btn.use-ssh', function(){
 
        $clone_by_id.hide();
 
        $clone_by_name.hide();
 
        $clone_ssh.show();
 
    });
 

	
 
    var cache = {}
 
    $("#download_options").select2({
 
        placeholder: _TM['Select changeset'],
 
        dropdownAutoWidth: true,
 
        query: function(query){
 
          var key = 'cache';
 
          var cached = cache[key] ;
 
          if(cached) {
 
            var data = {results: []};
 
            //filter results
 
            $.each(cached.results, function(){
 
                var section = this.text;
 
                var children = [];
 
                $.each(this.children, function(){
 
                    if(query.term.length == 0 || this.text.toUpperCase().indexOf(query.term.toUpperCase()) >= 0 ){
 
                        children.push({'id': this.id, 'text': this.text});
 
                    }
 
                });
 
                data.results.push({'text': section, 'children': children});
 
            });
 
            query.callback(data);
 
          }else{
 
              $.ajax({
 
                url: pyroutes.url('repo_refs_data', {'repo_name': ${h.js(c.repo_name)}}),
 
                data: {},
 
                dataType: 'json',
 
                type: 'GET',
 
                success: function(data) {
 
                  cache[key] = data;
 
                  query.callback({results: data.results});
 
                }
 
              });
 
          }
 
        }
 
    });
 
    // on change of download options
 
    $('#download_options').change(function(e){
 
       var new_cs = e.added
 

	
 
       for(let k in tmpl_links){
 
           var s = $('#'+k+'_link');
 
           if(s){
 
             var title_tmpl = ${h.jshtml(_('Download %s as %s') % ('__CS_NAME__','__CS_EXT__'))};
 
             title_tmpl= title_tmpl.replace('__CS_NAME__',new_cs.text);
 
             title_tmpl = title_tmpl.replace('__CS_EXT__',k);
 
             title_tmpl = '<i class="icon-file-zip"></i>'+ title_tmpl.html_escape();
 
             var url = tmpl_links[k].replace('__CS__',new_cs.id);
 
             var subrepos = $('#archive_subrepos').is(':checked');
 
             url = url.replace('__SUB__',subrepos);
 
             url = url.replace('__NAME__',title_tmpl);
 

	
 
             s.html(url);
 
           }
 
       }
 
    });
 

	
 
    var tmpl_links = {};
 
    %for cnt,archive in enumerate(c.db_repo_scm_instance._get_archives()):
 
      tmpl_links[${h.jshtml(archive['type'])}] = ${h.js(h.link_to('__NAME__', h.url('files_archive_home',repo_name=c.db_repo.repo_name, fname='__CS__'+archive['extension'],subrepos='__SUB__'),class_='btn btn-default btn-sm'))};
 
    %endfor
 
});
 
</script>
 

	
 
%if c.show_stats:
 
<script>'use strict';
 
$(document).ready(function(){
 
    var data = ${h.js(c.trending_languages)};
 
    var total = 0;
 
    var tbl = document.createElement('table');
 
    tbl.setAttribute('class','table');
 
    var cnt = 0;
 
    for (var i=0;i<data.length;i++){
 
    for (let i=0;i<data.length;i++){
 
        total+= data[i][1].count;
 
    }
 
    for (var i=0;i<data.length;i++){
 
    for (let i=0;i<data.length;i++){
 
        cnt += 1;
 

	
 
        var hide = cnt>2;
 
        var tr = document.createElement('tr');
 
        if (hide){
 
            tr.setAttribute('style','display:none');
 
            tr.setAttribute('class','stats_hidden');
 
        }
 
        var k = data[i][0];
 
        var obj = data[i][1];
 
        var percentage = Math.round((obj.count/total*100),2);
 

	
 
        var td1 = document.createElement('td');
 
        td1.width = 250;
 
        var trending_language_label = document.createElement('div');
 
        trending_language_label.innerHTML = obj.desc+" ("+k+")";
 
        td1.appendChild(trending_language_label);
 

	
 
        var td2 = document.createElement('td');
 
        td2.setAttribute('style','padding-right:14px !important');
 
        var trending_language = document.createElement('div');
 
        var nr_files = obj.count + ' ' + ${h.jshtml(_('files'))};
 

	
 
        trending_language.title = k+" "+nr_files;
 

	
 
        if (percentage>22){
 
            trending_language.innerHTML = "<b class='progress-bar' role='progressbar'"
 
                + "aria-valuemin='0' aria-valuemax='100' aria-valuenow='" + percentage
 
                + "' style='width: " + percentage + "%;'>" + percentage + "%, " + nr_files + "</b>";
 
        }
 
        else if (percentage>5){
 
            trending_language.innerHTML = "<b class='progress-bar' role='progressbar'"
 
                + "aria-valuemin='0' aria-valuemax='100' aria-valuenow='" + percentage
 
                + "' style='width: " + percentage + "%;'>" + percentage + "%</b>";
 
        }else{
 
            trending_language.innerHTML = "<b class='progress-bar' role='progressbar'"
 
                + "aria-valuemin='0' aria-valuemax='100' aria-valuenow='" + percentage
 
                + "' style='width: " + percentage + "%;'>&nbsp;</b>&nbsp;" + percentage + "%";
 
        }
 

	
 
        td2.appendChild(trending_language);
 

	
 
        tr.appendChild(td1);
 
        tr.appendChild(td2);
 
        tbl.appendChild(tr);
 
        if(cnt == 3){
 
            var show_more = document.createElement('tr');
 
            var td = document.createElement('td');
 
            let lnk = document.createElement('a');
 

	
 
            lnk.href='#';
 
            lnk.innerHTML = ${h.jshtml(_('Show more'))};
 
            lnk.id='code_stats_show_more';
 
            td.appendChild(lnk);
 

	
 
            show_more.appendChild(td);
 
            show_more.appendChild(document.createElement('td'));
 
            tbl.appendChild(show_more);
 
        }
 

	
 
    }
 
    if (data.length == 0) {
 
        tbl.innerHTML = '<tr><td>' + ${h.jshtml(_('No data ready yet'))} + '</td></tr>';
 
    }
 

	
 
    $('#lang_stats').append(tbl);
 
    $('#code_stats_show_more').click(function(){
 
        $('.stats_hidden').show();
 
        $('#code_stats_show_more').hide();
 
    });
 
});
 
</script>
 
%endif
 

	
 
</%def>
0 comments (0 inline, 0 general)