<!DOCTYPE html>
<html prefix="og: http://ogp.me/ns#" lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=5.0" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>2025-Tsuji/system/app.rb at master - HiroseLabo./2025-Tsuji</title>
<meta property="og:title" content="2025-Tsuji/system/app.rb at master - HiroseLabo./2025-Tsuji" />
<meta property="og:type" content="object" />
<meta property="og:url" content="http://localhost:8880/HiroseLabo./2025-Tsuji/blob/master/system/app.rb" />
<meta property="og:image" content="https://www.yatex.org/gitbucket/HiroseLabo./_avatar" />
<link rel="icon" href="https://www.yatex.org/gitbucket/assets/common/images/gitbucket.png?20251213122956" type="image/vnd.microsoft.icon" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="https://www.yatex.org/gitbucket/assets/vendors/google-fonts/css/source-sans-pro.css?20251213122956" rel="stylesheet">
<link href="https://www.yatex.org/gitbucket/assets/vendors/bootstrap-3.4.1/css/bootstrap.min.css?20251213122956" rel="stylesheet">
<link href="https://www.yatex.org/gitbucket/assets/vendors/octicons-4.4.0/octicons.min.css?20251213122956" rel="stylesheet">
<link href="https://www.yatex.org/gitbucket/assets/vendors/bootstrap-datetimepicker-4.17.44/css/bootstrap-datetimepicker.min.css?20251213122956" rel="stylesheet">
<link href="https://www.yatex.org/gitbucket/assets/vendors/colorpicker/css/bootstrap-colorpicker.min.css?20251213122956" rel="stylesheet">
<link href="https://www.yatex.org/gitbucket/assets/vendors/color-themes-for-google-code-prettify/github-v2.min.css?20251213122956" type="text/css" rel="stylesheet"/>
<link href="https://www.yatex.org/gitbucket/assets/vendors/facebox/facebox.css?20251213122956" rel="stylesheet"/>
<link href="https://www.yatex.org/gitbucket/assets/vendors/AdminLTE-2.4.2/css/AdminLTE.min.css?20251213122956" rel="stylesheet">
<link href="https://www.yatex.org/gitbucket/assets/vendors/AdminLTE-2.4.2/css/skins/skin-green-light.min.css?20251213122956" rel="stylesheet">
<link href="https://www.yatex.org/gitbucket/assets/vendors/font-awesome-4.7.0/css/font-awesome.min.css?20251213122956" rel="stylesheet">
<link href="https://www.yatex.org/gitbucket/assets/vendors/jquery-ui/jquery-ui.min.css?20251213122956" rel="stylesheet">
<link href="https://www.yatex.org/gitbucket/assets/vendors/jquery-ui/jquery-ui.structure.min.css?20251213122956" rel="stylesheet">
<link href="https://www.yatex.org/gitbucket/assets/vendors/jquery-ui/jquery-ui.theme.min.css?20251213122956" rel="stylesheet">
<link href="https://www.yatex.org/gitbucket/assets/common/css/gitbucket.css?20251213122956" rel="stylesheet">
<link href="https://www.yatex.org/gitbucket/assets/vendors/tipped/tipped.css?20251213122956" rel="stylesheet">
<script src="https://www.yatex.org/gitbucket/assets/vendors/jquery/jquery-3.5.1.min.js?20251213122956"></script>
<script src="https://www.yatex.org/gitbucket/assets/vendors/jquery-ui/jquery-ui.min.js?20251213122956"></script>
<script src="https://www.yatex.org/gitbucket/assets/vendors/dropzone/dropzone.min.js?20251213122956"></script>
<script src="https://www.yatex.org/gitbucket/assets/common/js/validation.js?20251213122956"></script>
<script src="https://www.yatex.org/gitbucket/assets/common/js/gitbucket.js?20251213122956"></script>
<script src="https://www.yatex.org/gitbucket/assets/vendors/bootstrap-3.4.1/js/bootstrap.min.js?20251213122956"></script>
<script src="https://www.yatex.org/gitbucket/assets/vendors/bootstrap3-typeahead/bootstrap3-typeahead.min.js?20251213122956"></script>
<script src="https://www.yatex.org/gitbucket/assets/vendors/bootstrap-datetimepicker-4.17.44/js/moment.min.js?20251213122956"></script>
<script src="https://www.yatex.org/gitbucket/assets/vendors/bootstrap-datetimepicker-4.17.44/js/bootstrap-datetimepicker.min.js?20251213122956"></script>
<script src="https://www.yatex.org/gitbucket/assets/vendors/colorpicker/js/bootstrap-colorpicker.min.js?20251213122956"></script>
<script src="https://www.yatex.org/gitbucket/assets/vendors/google-code-prettify/prettify.js?20251213122956"></script>
<script src="https://www.yatex.org/gitbucket/assets/vendors/elastic/jquery.elastic.source.js?20251213122956"></script>
<script src="https://www.yatex.org/gitbucket/assets/vendors/facebox/facebox.js?20251213122956"></script>
<script src="https://www.yatex.org/gitbucket/assets/vendors/jquery-hotkeys/jquery.hotkeys.js?20251213122956"></script>
<script src="https://www.yatex.org/gitbucket/assets/vendors/jquery-textcomplete-1.8.4/jquery.textcomplete.min.js?20251213122956"></script>
<script src="https://www.yatex.org/gitbucket/assets/vendors/tipped/tipped.min.js?20251213122956"></script>
<meta name="go-import" content="www.yatex.org/gitbucket/HiroseLabo./2025-Tsuji git https://www.yatex.org/gitbucket/git/HiroseLabo./2025-Tsuji.git" />
<script src="https://www.yatex.org/gitbucket/assets/vendors/AdminLTE-2.4.2/js/adminlte.min.js?20251213122956" type="text/javascript"></script>
<style type="text/css">.content, .sidebar, .skin-green-light div.main-sidebar {
background: #efe;
}</style>
</head>
<body class="skin-green-light page-load sidebar-mini ">
<div class="wrapper">
<header class="main-header">
<a href="https://www.yatex.org/gitbucket/" class="logo">
<span class="logo-mini"><img src="https://www.yatex.org/gitbucket/assets/common/images/gitbucket.svg?20251213122956" alt="GitBucket" /></span>
<span class="logo-lg">
<img src="https://www.yatex.org/gitbucket/assets/common/images/gitbucket.svg?20251213122956" alt="GitBucket" />
<span class="header-title strong">GitBucket</span>
</span>
</a>
<nav class="navbar navbar-static-top" role="navigation">
<!-- Sidebar toggle button-->
<a href="#" class="sidebar-toggle" data-toggle="push-menu" role="button" title="Toggle navigation">
<span class="sr-only">Toggle navigation</span>
</a>
<form id="search" action="https://www.yatex.org/gitbucket/search" method="GET" class="pc navbar-form navbar-left" role="search">
<div class="form-group">
<input type="text" name="query" id="navbar-search-input" class="form-control" placeholder="Find a repository" aria-label="Search"/>
</div>
</form>
<ul class="pc nav navbar-nav">
<li><a href="https://www.yatex.org/gitbucket/dashboard/pulls">Pull requests</a></li>
<li><a href="https://www.yatex.org/gitbucket/dashboard/issues">Issues</a></li>
<li><a href="https://www.yatex.org/gitbucket/gist">Snippets</a></li>
</ul>
<div class="navbar-custom-menu">
<ul class="nav navbar-nav">
<li>
<a href="https://www.yatex.org/gitbucket/signin?redirect=%2FHiroseLabo.%2F2025-Tsuji%2Fblob%2Fmaster%2Fsystem%2Fapp.rb" class="pull-right" id="signin">Sign in</a>
</li>
</ul>
</div>
</nav>
</header>
<div class="main-sidebar">
<div class="sidebar">
<ul class="sidebar-menu">
<li class = "menu-item-hover active">
<a href="https://www.yatex.org/gitbucket/HiroseLabo./2025-Tsuji">
<i class="menu-icon octicon octicon-code"></i>
<span>Files</span>
</a>
</li>
<li class = "menu-item-hover ">
<a href="https://www.yatex.org/gitbucket/HiroseLabo./2025-Tsuji/branches">
<i class="menu-icon octicon octicon-git-branch"></i>
<span>Branches</span>
<span class="pull-right-container"><span class="label label-primary pull-right">1</span></span>
</a>
</li>
<li class = "menu-item-hover ">
<a href="https://www.yatex.org/gitbucket/HiroseLabo./2025-Tsuji/releases">
<i class="menu-icon octicon octicon-tag"></i>
<span>Releases</span>
</a>
</li>
<li class = "menu-item-hover ">
<a href="https://www.yatex.org/gitbucket/HiroseLabo./2025-Tsuji/issues">
<i class="menu-icon octicon octicon-issue-opened"></i>
<span>Issues</span>
</a>
</li>
<li class = "menu-item-hover ">
<a href="https://www.yatex.org/gitbucket/HiroseLabo./2025-Tsuji/pulls">
<i class="menu-icon octicon octicon-git-pull-request"></i>
<span>Pull requests</span>
</a>
</li>
<li class = "menu-item-hover ">
<a href="https://www.yatex.org/gitbucket/HiroseLabo./2025-Tsuji/issues/labels">
<i class="menu-icon octicon octicon-tag"></i>
<span>Labels</span>
</a>
</li>
<li class = "menu-item-hover ">
<a href="https://www.yatex.org/gitbucket/HiroseLabo./2025-Tsuji/issues/priorities">
<i class="menu-icon octicon octicon-flame"></i>
<span>Priorities</span>
</a>
</li>
<li class = "menu-item-hover ">
<a href="https://www.yatex.org/gitbucket/HiroseLabo./2025-Tsuji/issues/milestones">
<i class="menu-icon octicon octicon-milestone"></i>
<span>Milestones</span>
</a>
</li>
<li class = "menu-item-hover ">
<a href="https://www.yatex.org/gitbucket/HiroseLabo./2025-Tsuji/wiki">
<i class="menu-icon octicon octicon-book"></i>
<span>Wiki</span>
</a>
</li>
</ul>
</div>
</div>
<div class="content-wrapper">
<div class="content body clearfix">
<div class="headbar">
<div class="container">
<div class="head">
<div class="pull-right">
<a class="btn btn-default btn-sm" href="https://www.yatex.org/gitbucket/signin?redirect=https%3A%2F%2Fwww.yatex.org%2Fgitbucket%2FHiroseLabo.%2F2025-Tsuji">
<span class="strong"><i class="octicon octicon-repo-forked"></i>Fork</span><span class="muted">: 0</span>
</a>
<form id="fork-form" method="post" action="https://www.yatex.org/gitbucket/HiroseLabo./2025-Tsuji/fork" style="display: none;">
<input type="hidden" name="account" value=""/>
</form>
</div>
<i class="mega-octicon octicon-repo"></i>
<a href="https://www.yatex.org/gitbucket/HiroseLabo.">HiroseLabo.</a> / <a href="https://www.yatex.org/gitbucket/HiroseLabo./2025-Tsuji" class="strong">2025-Tsuji</a>
</div>
</div>
</div>
<style>
.prettyprint {
tab-size: 8
}
</style>
<div class="head">
<div class="pull-right hide-if-blame"><div class="btn-group">
<a href="https://www.yatex.org/gitbucket/HiroseLabo./2025-Tsuji/blob/b58ce336b872039f7e0caba06d28f263cd7af6b7/system/app.rb" data-hotkey="y" style="display: none;">Transfer to URL with SHA</a>
<a href="https://www.yatex.org/gitbucket/HiroseLabo./2025-Tsuji/find/master" class="btn btn-sm btn-default" data-hotkey="t">Find file</a>
</div></div>
<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>
<div id="branchCtrlWrapper" style="display:inline;">
<div class="btn-group" >
<button class="dropdown-toggle btn btn-default btn-sm" data-toggle="dropdown">
<span class="muted">branch:</span>
<span class="strong"
style="display:inline-block; vertical-align:bottom; overflow-x:hidden; max-width:200px; text-overflow:ellipsis">
master
</span>
<span class="caret"></span>
</button>
<ul class="dropdown-menu">
<li>
<ul class="nav nav-tabs">
<li class="active" id="branch-control-tab-branches"><a href="javascript:void(0);" class="nav-item" id="nav-item-branches">Branches</a></li>
<li id="branch-control-tab-tags"><a href="javascript:void(0);" class="nav-item" id="nav-item-tags">Tags</a></li>
<li><button id="branch-control-close" class="pull-right">×</button></li>
</ul>
<li>
<input id="branch-control-input" type="text" class="form-control input-sm dropdown-filter-input"/>
</li>
<li><a href="https://www.yatex.org/gitbucket/HiroseLabo./2025-Tsuji/blob/master/system/app.rb">
<i class="octicon octicon-check"></i>
master</a></li>
</li>
</ul>
</div>
<script>
$(function(){
$('#branch-control-input').parent().click(function(e) {
e.stopPropagation();
});
$('#branch-control-close').click(function() {
$('[data-toggle="dropdown"]').parent().removeClass('open');
});
$('#branch-control-input').keyup(function() {
updateBranchControlListFilter();
});
$('.btn-group').click(function() {
$('#branch-control-input').val('');
//$('.dropdown-menu li').show();
$('#create-branch').hide();
});
$('#nav-item-branches').click(function(e) {
e.stopPropagation();
updateBranchControlList('branches');
});
$('#nav-item-tags').click(function(e) {
e.stopPropagation();
updateBranchControlList('tags');
});
function updateBranchControlList(active) {
if (active == 'branches') {
$('li#branch-control-tab-branches').addClass('active');
$('li#branch-control-tab-tags').removeClass('active');
$('li.branch-control-item-branch').show();
$('li.branch-control-item-branch > a').addClass('active');
$('li.branch-control-item-tag').hide();
$('li.branch-control-item-tag > a').removeClass('active');
$('#branch-control-input').attr('placeholder', 'Find branch ...');
} else if (active == 'tags') {
$('li#branch-control-tab-branches').removeClass('active');
$('li#branch-control-tab-tags').addClass('active');
$('li.branch-control-item-branch').hide();
$('li.branch-control-item-branch > a').removeClass('active');
$('li.branch-control-item-tag').show();
$('li.branch-control-item-tag > a').addClass('active');
$('#branch-control-input').attr('placeholder', 'Find tag ...');
}
updateBranchControlListFilter();
}
function updateBranchControlListFilter() {
const inputVal = $('#branch-control-input').val();
$.each($('#branch-control-input').parent().parent().find('a.active').not('.nav-item'), function(index, elem) {
if (!inputVal || !elem.text.trim() || elem.text.trim().toLowerCase().indexOf(inputVal.toLowerCase()) >= 0) {
$(elem).parent().show();
} else {
$(elem).parent().hide();
}
});
if ($('li#branch-control-tab-branches.active').length > 0) {
}
}
// Initialize the branch control list
updateBranchControlList('branches');
});
</script>
</div>
<a href="https://www.yatex.org/gitbucket/HiroseLabo./2025-Tsuji/tree/master">2025-Tsuji</a> /
<a href="https://www.yatex.org/gitbucket/HiroseLabo./2025-Tsuji/tree/master/system">system</a> /
app.rb
</div>
<div class="box-header" style="line-height: 28px;">
<a href="https://www.yatex.org/gitbucket/T-keita" class=""><img src="https://www.gravatar.com/avatar/5092dd69ff94eac90ec071b1df132981?s=20&d=retro&r=g" class="avatar-mini" style="width: 20px; height: 20px;"
alt="@tsuji keita" /></a>
<a href="https://www.yatex.org/gitbucket/T-keita" class="username strong">tsuji keita</a>
<span class="muted">
<span data-toggle="tooltip" title="2025-12-15 18:01:52">
2 minutes ago
</span>
</span>
<span class="label label-default">5 KB</span>
<a href="https://www.yatex.org/gitbucket/HiroseLabo./2025-Tsuji/commit/b58ce336b872039f7e0caba06d28f263cd7af6b7" class="commit-message">Add files via upload</a>
<div class="btn-group pull-right">
<a class="btn btn-sm btn-default" href="https://www.yatex.org/gitbucket/HiroseLabo./2025-Tsuji/raw/b58ce336b872039f7e0caba06d28f263cd7af6b7/system/app.rb">Raw</a>
<a class="btn btn-sm btn-default blame-action" href="https://www.yatex.org/gitbucket/HiroseLabo./2025-Tsuji/blame/b58ce336b872039f7e0caba06d28f263cd7af6b7/system/app.rb"
data-url="https://www.yatex.org/gitbucket/HiroseLabo./2025-Tsuji/get-blame/b58ce336b872039f7e0caba06d28f263cd7af6b7/system/app.rb" data-repository="https://www.yatex.org/gitbucket/HiroseLabo./2025-Tsuji">Blame</a>
<a class="btn btn-sm btn-default" href="https://www.yatex.org/gitbucket/HiroseLabo./2025-Tsuji/commits/master/system/app.rb">History</a>
</div>
</div>
<div class="box-content-bottom">
<pre class="prettyprint linenums blob no-renderable ">require "sinatra"
require "sinatra/json"
require "sqlite3"
require "json"
require "securerandom"
require "bcrypt"
set :bind, '0.0.0.0'
set :port, 9292
set :public_folder, File.join(__dir__, "public")
# ✅ セッション設定
use Rack::Session::Cookie,
key: 'rack.session',
path: '/',
same_site: :lax,
secure: false,
secret: SecureRandom.hex(64)
# ✅ CORS(風馬さんのIPを明示)
before do
response.headers["Access-Control-Allow-Origin"] = "http://172.20.16.218:4567"
response.headers["Access-Control-Allow-Credentials"] = "true"
response.headers["Access-Control-Allow-Headers"] = "Content-Type"
end
options "*" do
response.headers["Access-Control-Allow-Origin"] = "http://172.20.16.218:4567"
response.headers["Access-Control-Allow-Credentials"] = "true"
response.headers["Access-Control-Allow-Headers"] = "Content-Type"
response.headers["Access-Control-Allow-Methods"] = "GET, POST, OPTIONS"
200
end
# ✅ DB接続(風馬さんのDBに統一)
DB = SQLite3::Database.new "database.db"
DB.results_as_hash = true
# ✅ テーブル作成(風馬さん構成に統一)
DB.execute <<-SQL
CREATE TABLE IF NOT EXISTS requests (
id INTEGER PRIMARY KEY AUTOINCREMENT,
category TEXT NOT NULL,
description TEXT,
latitude REAL NOT NULL,
longitude REAL NOT NULL,
start_time TEXT,
end_time TEXT,
info_level REAL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
SQL
DB.execute <<-SQL
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT UNIQUE NOT NULL,
password_hash TEXT NOT NULL,
role TEXT NOT NULL CHECK(role IN ('supporter', 'requester')),
trust_score REAL DEFAULT 0.5,
info_level REAL DEFAULT 0.5,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
SQL
# ✅ ログイン必須
def require_login
unless session[:user_id]
halt 401, json(error: "ログインしてください")
end
end
# ✅ ユーザー登録(roleとinfo_levelを受け取る)
post "/api/signup" do
content_type :json
data = JSON.parse(request.body.read) rescue {}
username = data["username"]
password = data["password"]
role = data["role"] || "requester"
info_level = data["info_level"] || 0.5
halt 400, json(error: "username, password, role が必要です") unless username && password && role
password_hash = BCrypt::Password.create(password)
begin
DB.execute("INSERT INTO users (username, password_hash, role, info_level) VALUES (?, ?, ?, ?)",
[username, password_hash, role, info_level])
json(status: "success", message: "ユーザー登録成功", user: username, role: role)
rescue SQLite3::ConstraintException
halt 400, json(error: "そのユーザー名は既に使われています")
end
end
# ✅ ログイン
post "/api/login" do
content_type :json
data = JSON.parse(request.body.read) rescue {}
username = data["username"]
password = data["password"]
halt 400, json(error: "username and password required") unless username && password
user = DB.execute("SELECT * FROM users WHERE username = ?", [username]).first
halt 401, json(error: "ユーザーが存在しません") unless user
if BCrypt::Password.new(user["password_hash"]) == password
session[:user_id] = user["id"]
json(
status: "success",
message: "ログイン成功",
user: user["username"],
role: user["role"],
trust_score: user["trust_score"],
info_level: user["info_level"]
)
else
halt 401, json(error: "パスワードが違います")
end
end
# ✅ ログアウト
post "/api/logout" do
session.clear
json(status: "success", message: "ログアウトしました")
end
# ✅ ログイン状態確認
get "/api/me" do
require_login
user = DB.execute("SELECT id, username, role, trust_score, info_level FROM users WHERE id = ?", [session[:user_id]]).first
json user
end
# ✅ 依頼送信
post "/api/requests" do
require_login
content_type :json
data = JSON.parse(request.body.read) rescue {}
category = data["category"]
description = data["description"] || "依頼内容"
latitude = data["latitude"] || 38.9
longitude = data["longitude"] || 139.8
start_time = data["start_time"] || Time.now.strftime("%Y-%m-%d %H:%M")
end_time = data["end_time"]
info_level = data["info_level"] || 0.5
halt 400, json(error: "category required") unless category
DB.execute("INSERT INTO requests (category, description, latitude, longitude, start_time, end_time, info_level)
VALUES (?, ?, ?, ?, ?, ?, ?)",
[category, description, latitude, longitude, start_time, end_time, info_level])
id = DB.last_insert_row_id
json(
id: id,
category: category,
description: description,
latitude: latitude,
longitude: longitude,
start_time: start_time,
info_level: info_level
)
end
# ✅ 依頼一覧取得
get "/api/requests" do
require_login
content_type :json
rows = DB.execute("SELECT * FROM requests ORDER BY id DESC")
json rows
end
# ✅ フロント配信
get "/" do
send_file File.join(settings.public_folder, "index.html")
end
</pre>
</div>
</div>
</div>
<script>
$(function(){
$('a[rel*=facebox]').facebox({
'loadingImage': 'https://www.yatex.org/gitbucket/assets/vendors/facebox/loading.gif?20251213122956',
'closeImage': 'https://www.yatex.org/gitbucket/assets/vendors/facebox/closelabel.png?20251213122956'
});
$(document).on("click", ".js-fork-owner-select-target", function() {
var account = $(this).text().replace("@", "");
$("#account").val(account);
$("#fork").submit();
});
});
</script>
</div>
<script>
$(function(){
$(".sidebar-toggle").on('click', function(e){
$.post('https://www.yatex.org/gitbucket/sidebar-collapse', { collapse: !$('body').hasClass('sidebar-collapse') });
});
});
</script>
<script>
$('head').append($('<link rel="stylesheet" type="text/css" href="https://www.yatex.org/gitbucket/user.css">'))
</script>
</body>
</html>
<script>
$(window).on('load', function(){
window.onhashchange = function(){
updateHighlighting();
}
const pre = $('pre.prettyprint');
function updateSourceLineNum() {
$('.source-line-num').remove();
const pos = pre.find('ol.linenums').position();
if (pos) {
$('<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){
let 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);
}
let i = 0;
for(i = 0; i < pos.length - 1; i++){
if(pos[i + 1].top > e.pageY){
break;
}
}
const line = pos[i].id.replace(/^L/,'');
const hash = location.hash;
const baseUrl = location.toString().split("#")[0];
if (e.shiftKey == true && hash.match(/#L\d+(-L\d+)?/)) {
const fragments = hash.split('-');
window.history.pushState('', '', baseUrl + fragments[0] + '-L' + line);
} else {
const p = $("#L" + line).attr('id', '');
window.history.pushState('', '', baseUrl + '#L' + line);
p.attr('id','L' + line);
}
$("#branchCtrlWrapper .btn .muted").text("tree:");
$("#branchCtrlWrapper .btn .strong").text("b58ce336b8");
getSelection().empty();
updateHighlighting();
}).appendTo(pre);
updateHighlighting();
} else {
// Maybe code view is not initialized yet. Retry until succeed.
setTimeout(updateSourceLineNum, 300);
}
}
const 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(){
const m = /\/(blame|blob)(\/.*)$/.exec(location.href);
const mode = m[1];
$('.blame-action').toggleClass("active", mode=='blame').attr('href', repository + (m[1] == 'blame' ? '/blob' : '/blame') + m[2]);
if(pre.parents("div.box-content-bottom").find(".blame").length){
pre.parent().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");
const base = $('<div class="blame">').css({height: pre.height()}).prependTo(pre.parents("div.box-content-bottom"));
base.parent().addClass("blame-container");
updateSourceLineNum();
$.get($('.blame-action').data('url')).done(function(data){
let blame = data.blame;
let lastDiv;
const now = new Date().getTime();
const index = [];
for(let i = 0; i < blame.length; i++){
for(let j = 0; j < blame[i].lines.length; j++){
index[blame[i].lines[j]] = blame[i];
}
}
$('pre.prettyprint ol.linenums li').each(function(i, e){
const p = $(e).position();
const 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];
const 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;
};
$(document).on('expanded.pushMenu collapsed.pushMenu', function(e){
setTimeout(updateBlame, 300);
});
updateBlame();
});
let scrolling = false;
/**
* Highlight lines which are specified by URL hash.
*/
function updateHighlighting() {
const hash = location.hash;
const isDark = false;
if (hash.match(/#L\d+(-L\d+)?/)) {
if (isDark) {
$('li.highlight-dark').removeClass('highlight-dark');
} else {
$('li.highlight').removeClass('highlight');
}
const fragments = hash.substr(1).split('-');
if (fragments.length == 1) {
if (isDark) {
$('#' + fragments[0]).addClass('highlight-dark');
} else {
$('#' + fragments[0]).addClass('highlight');
}
if(!scrolling){
$(window).scrollTop($('#' + fragments[0]).offset().top);
}
} else if(fragments.length > 1){
const start = parseInt(fragments[0].substr(1));
const end = parseInt(fragments[1].substr(1));
for (let i = start; i <= end; i++) {
if (isDark) {
$('#L' + i).addClass('highlight-dark');
} else {
$('#L' + i).addClass('highlight');
}
}
if (!scrolling) {
$(window).scrollTop($('#' + fragments[0]).offset().top);
}
}
}
scrolling = true;
}
</script>