fish-shell/share/tools/web_config/index.html

1050 lines
22 KiB
HTML

<html>
<head>
<style type="text/css">
body {
background-color: #292929;
font-family: Courier, "Courier New", monospace;
color: white;
}
#ancestor {
width: 800px;
margin-left: auto;
margin-right: auto;
margin-top: 25px;
}
#parent {
width: 100%;
min-height: 480px;
margin-top: 12px;
}
#tab_parent {
display: table;
width: 100%;
height: 50px;;
}
.tab {
display: table-cell;
border: 1px solid #111;
border-right: none;
padding-bottom: 15px;
padding-top: 15px;
font-size: 17pt;
text-align: center;
width: 25%;
background-color: #292929;
cursor: pointer;
}
#tab_parent :first-child {
border-top-left-radius: 8px;
}
#tab_parent :last-child {
border-right: 1px solid #111;
border-top-right-radius: 8px;
}
.tab_first {
border-top-left-radius: 5px;
border-bottom-left-radius: 5px;
}
.tab_last {
border-top-right-radius: 5px;
border-bottom-right-radius: 5px;
}
.selected_tab {
background-color: black;
border-color: black;
}
#tab_contents {
padding-top: 35px;
width: 100%;
background-color: black;
border-bottom-left-radius: 8px;
border-bottom-right-radius: 8px;
margin-bottom: 20px;
}
.footer {
clear: both;
height: 30px;
}
#master_detail_table {
display: table;
margin-top: 10px;
margin-left: 12px;
margin-right: 12px;
}
#master {
display: table-cell;
text-align: right;
min-width: 200px;
font-size: 16pt;
padding-bottom: 5px;
margin-top: -7px;
}
#detail {
display: table-cell;
border: 1px solid #555;
background-color: #181818;
padding-top: 30px;
padding-bottom: 20px;
padding-left: 30px;
padding-right: 30px;
border-radius: 5;
}
#detail_function {
white-space: pre-wrap;
width: 100%;
font-size: 11pt;
color: #BBB;
}
.master_element {
padding-top: 6px;
padding-bottom: 11px;
padding-left: 5px;
padding-right: 22px;
font-size: 12pt;
/* Make our border overlap the detail, even if we're unselected (so it doesn't jump when selected) */
position: relative;
left: 1px;
}
.selected_master_elem {
border: 1px solid #555;
border-right: none;
background-color: #181818;
border-top-left-radius: 5;
border-bottom-left-radius: 5;
/* Pad one less than .master_element, to accomodate our border. */
padding-top: 5px;
padding-bottom: 10px;
padding-left: 4px;
}
.master_element_text {
text-decoration: none;
padding-bottom: 1px;
border-bottom: 1px solid white;
}
#colorpicker_term256 {
border: solid #444 1px;
}
.colorpicker_modifiers {
margin-top: 10px;
display:inline-block;
margin-left: auto;
margin-right: auto;
color: #AAA;
font-size: smaller;
}
.colorpicker_modifier_cell {
cursor: pointer;
display:inline-block;
text-align: center;
border: groove #333 2px;
padding: 5px;
margin-top: 5px;
margin-left: auto;
margin-right: auto;
}
.modifier_cell_selected {
color: #CCC;
border-color: #AAA;
background-color: #444;
}
#data_table {
table-layout:fixed;
color: #CCC;
width: 100%;
padding-left: 10px;
padding-right: 10px;
}
.data_table_row {
}
.data_table_cell {
padding-top: 5px;
padding-bottom: 5px;
vertical-align: top;
overflow:hidden;
border-bottom: #444 dotted 1px;
word-wrap: break-word;
}
.no_overflow {
text-overflow: ellipsis;
white-space: nowrap;
}
.colorpicker_target {
margin: 0px;
height: 50px;
margin-bottom: -50px;
}
.colorpicker_target_tab {
cursor: pointer;
color: #555;
border: solid 1px #555;
padding-top: 5px;
padding-bottom: 5px;
padding-left: 7px;
padding-right: 7px;
display: inline-block;
background-color: black;
margin-right: -2px;
min-width: 110px;
text-align: center;
position: relative;
bottom: 47px;
}
.colorpicker_target_selected {
background-color: #181818; /* same as #detail */
color: white;
}
.colorpicker_term256_row {
}
.colorpicker_term256_cell {
width: 29;
height: 29;
}
.colorpicker_cell_selected {
border: dashed white 3px;
width: 23;
height: 23;
}
.error_msg {
color: red;
font-size: 12pt;
margin-left: 24pt;
margin-top: 5pt;
margin-bottom: 5pt;
}
</style>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript">
function show_error(msg) {
$('#global_error').text(msg)
}
function request_failed(jqXHR, textStatus, errorThrown) {
msg = ''
if (textStatus == "timeout") {
msg = 'The request timed out. Perhaps the server has shut down or is hung.'
} else if (textStatus == "error") {
msg = 'The request received an error.'
if (jqXHR.status == 0)
msg = msg + ' Perhaps the server has shut down.'
} else if (msg == 'abort') {
msg = 'The request aborted.'
} else if (msg == 'parsererror') {
msg = 'The request experienced a parser error.'
} else {
msg = 'The request had an unknown error "' + textStatus + '."'
}
if (errorThrown.length > 0) {
msg = msg + ' The HTTP reply returned ' + errorThrown
}
show_error(msg)
}
/* Runs a GET request, parses the JSON, and invokes the handler for each element in it. The JSON result is assumed to be an array. */
function run_get_request(url, handler) {
$.ajax({
type: "GET",
url: url,
success: function(data){
$('#global_error').text('')
$.each($.parseJSON(data), function(idx, contents) {
handler(contents)
})
},
error: request_failed
})
}
/* As above but with POST request. */
function run_post_request(url, data_map, handler) {
$.ajax({
type: "POST",
url: url,
data: data_map,
success: function(data){
$('#global_error').text('')
$.each($.parseJSON(data), function(idx, contents) {
handler(contents)
})
},
error: request_failed
})
}
function rgb_to_hsl(r, g, b){
r /= 255, g /= 255, b /= 255;
var max = Math.max(r, g, b), min = Math.min(r, g, b);
var h, s, l = (max + min) / 2;
if(max == min){
h = s = 0; // achromatic
}else{
var d = max - min;
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
switch(max){
case r: h = (g - b) / d + (g < b ? 6 : 0); break;
case g: h = (b - r) / d + 2; break;
case b: h = (r - g) / d + 4; break;
}
h /= 6;
}
return [h, s, l];
}
function hsl_to_rgb(h, s, l){
var r, g, b;
if(s == 0){
r = g = b = l; // achromatic
}else{
function hue2rgb(p, q, t){
if(t < 0) t += 1;
if(t > 1) t -= 1;
if(t < 1/6) return p + (q - p) * 6 * t;
if(t < 1/2) return q;
if(t < 2/3) return p + (q - p) * (2/3 - t) * 6;
return p;
}
var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
var p = 2 * l - q;
r = hue2rgb(p, q, h + 1.0/3);
g = hue2rgb(p, q, h);
b = hue2rgb(p, q, h - 1.0/3);
}
return [r * 255, g * 255, b * 255]
}
/* Given an RGB color as a hex string, like FF0033, convert to HSL, apply the function to adjust its lightness, then return the new color as an RGB string */
function adjust_lightness(color_str, func) {
/* Hack to handle for example F00 */
if (color_str.length == 3) {
color_str = color_str[0] + color_str[0] + color_str[1] + color_str[1] + color_str[2] + color_str[2]
}
rgb = parseInt(color_str, 16)
r = (rgb >> 16) & 0xFF
g = (rgb >> 8) & 0xFF
b = (rgb >> 0) & 0xFF
hsl = rgb_to_hsl(r, g, b)
new_lightness = func(hsl[2])
function to_int_str(val) {
str = Math.round(val).toString(16)
while (str.length < 2)
str = '0' + str
return str
}
new_rgb = hsl_to_rgb(hsl[0], hsl[1], new_lightness)
return to_int_str(new_rgb[0]) + to_int_str(new_rgb[1]) + to_int_str(new_rgb[2])
}
/* Given a color, compute the master text color for it, by giving it a minimum brightness */
function master_color_for_color(color_str) {
return adjust_lightness(color_str, function(lightness){
if (lightness < .33) {
lightness = .33
}
return lightness
})
}
function switch_tab(new_tab) {
/* Switch selected tab */
$(".selected_tab").removeClass("selected_tab")
$('#' + new_tab).addClass("selected_tab")
/* Empty master element */
$('#master').empty()
/* Unselect some things */
$(".colorpicker_cell_selected").removeClass('colorpicker_cell_selected')
/* Hide some things */
$('#master_detail_table').hide()
$('#detail_colorpicker').hide()
$('#detail_function').hide()
$('#data_table').hide()
$('#data_table').empty()
/* Load something new */
if (new_tab == 'tab_colors') {
/* Keep track of whether this is the first element */
var first = true
run_get_request('/colors/', function(key_and_values){
var key = key_and_values[0]
var style = new Style(key_and_values[1])
style_map[key] = style
elem = create_master_element(key, style.color, '', select_color_master_element)
if (first) {
/* It's the first element, so select it, so something gets selected */
select_color_master_element(elem)
first = false
}
})
$('#detail_colorpicker').show()
$('#master_detail_table').show()
} else if (new_tab == 'tab_functions') {
/* Keep track of whether this is the first element */
var first = true
run_get_request('/functions/', function(contents){
elem = create_master_element(contents, 'AAAAAA', '11pt', select_function_master_element)
if (first) {
/* It's the first element, so select it, so something gets selected */
select_function_master_element(elem)
first = false
}
})
$('#detail_function').show()
$('#master_detail_table').show()
} else if (new_tab == 'tab_variables') {
run_get_request('/variables/', function(contents){
var name = contents[0]
var value = contents[1]
var flags = contents[2]
create_data_table_element([name, value])
})
$('#data_table').show()
} else if (new_tab == 'tab_history') {
run_get_request('/history/', function(contents){
create_data_table_element([contents])
})
$('#data_table').show()
} else {
alert("Unknown tab");
}
return false
}
function current_master_element_name() {
/* Get the name of the current color variable, like 'autosuggestion' */
var elems = $('.selected_master_elem')
if (elems.length == 0) {
return ''
}
elem = elems[0]
if (elem.id.indexOf('master_') != 0) {
show_error('Unknown color variable')
return ''
}
return elem.id.substring(7)
}
function is_foreground() {
/* Returns true if the selected tab is foreground, false if it's background */
who = $('.colorpicker_target_selected')
if (who.length == 0) {
show_error('Not sure if we are in foreground or background')
return false
}
return who[0].id == 'foreground'
}
function current_style() {
/* Returns the style object corresponding to the current color variable */
return style_map[current_master_element_name()]
}
function reflect_style() {
/* Unselect everything */
$('.colorpicker_cell_selected').removeClass('colorpicker_cell_selected')
$('.modifier_cell_selected').removeClass('modifier_cell_selected')
/* Now update the color picker with the current style (if we have one) */
style = current_style()
if (style) {
/* Use this function to make a color that contrasts well with the given color */
var adjust = .5
function compute_constrast(lightness){
var new_lightness = lightness + adjust
if (new_lightness > 1.0 || new_lightness < 0.0) {
new_lightness -= 2 * adjust
}
return new_lightness
}
color = is_foreground() ? style.color : style.background_color
var color_cell = $('#color_' + color)
color_cell.addClass('colorpicker_cell_selected')
color_cell.css('border-color', adjust_lightness(is_foreground() ? style.color : style.background_color, compute_constrast))
if (style.underline) {
$('#modifier_underline').addClass('modifier_cell_selected')
}
/* In the master list, ensure the color is visible against the dark background. If we're deselecting, use COLOR_NORMAL */
master_color = style.color ? master_color_for_color(style.color) : COLOR_NORMAL
$('.selected_master_elem').children('.master_element_text').css({'color': master_color, 'border-bottom-color': master_color})
}
}
function select_master_element(elem) {
$('.selected_master_elem').removeClass('selected_master_elem')
$(elem).addClass('selected_master_elem')
}
function select_color_master_element(elem) {
select_master_element(elem)
/* This changed the current style; reflect that */
reflect_style()
}
function select_function_master_element(elem) {
select_master_element(elem)
run_post_request('/get_function/', {
what: current_master_element_name()
}, function(contents){
/* Replace leading tabs and groups of four spaces at the beginning of a line with two spaces. */
lines = contents.split('\n')
rx = /^[\t ]+/
for (var i=0; i < lines.length; i++) {
line = lines[i]
/* Get leading tabs and spaces */
whitespace_arr = rx.exec(line)
if (whitespace_arr) {
/* Replace four spaces with two spaces, and tabs with two spaces */
var whitespace = whitespace_arr[0]
new_whitespace = whitespace.replace(/( )|(\t)/g, ' ')
lines[i] = new_whitespace + line.slice(whitespace.length)
}
}
munged_contents = lines.join('\n')
$('#detail_function').text(munged_contents)
});
}
function post_style_to_server() {
style = current_style()
if (! style)
return
run_post_request('/set_color/', {
what: current_master_element_name(),
color: style.color,
background_color: style.background_color,
bold: style.bold,
underline: style.underline
}, function(contents){
})
}
function picked_color_cell(cell) {
/* Get the color to set */
if (cell.id.indexOf('color_') != 0) {
show_error('Unknown cell')
return
}
color = cell.id.substring(6)
/* Determine whether we are going to select or unselect this cell */
var deselect = $(cell).hasClass('colorpicker_cell_selected')
/* Get the current style */
style = current_style()
if (! style)
return
/* Change the color */
if (is_foreground()) {
style.color = deselect ? '' : color
} else {
style.background_color = deselect ? '' : color
}
/* Show our changes */
reflect_style()
/* Tell the server */
post_style_to_server()
}
function picked_modifier(cell) {
style = current_style()
if (! style)
return
if (cell.id == 'modifier_underline') {
style.underline = ! style.underline
} else if (cell.id == 'modifier_bold') {
style.bold = ! style.bold
} else {
show_error('Unknown cell')
}
reflect_style()
post_style_to_server()
}
function picked_colorpicker_target(tab) {
/* The function that gets called when a tab is selected */
$('.colorpicker_target_selected').removeClass('colorpicker_target_selected')
$(tab).addClass('colorpicker_target_selected')
reflect_style()
}
/* Given a color name, like 'normal' or 'red' or 'FF00F0', return an RGB color string (or empty string) */
function interpret_color(str) {
str = str.toLowerCase()
if (str == 'black') return '000000'
if (str == 'red') return 'FF0000'
if (str == 'green') return '00FF00'
if (str == 'brown') return '725000'
if (str == 'yellow') return 'FFFF00'
if (str == 'blue') return '0000FF'
if (str == 'magenta') return 'FF00FF'
if (str == 'purple') return 'FF00FF'
if (str == 'cyan') return '00FFFF'
if (str == 'white') return 'FFFFFF'
if (str == 'normal') return ''
return str
}
/* Class representing a color style */
function Style(stuff) {
this.color = interpret_color(stuff[0])
this.background_color = interpret_color(stuff[1])
this.bold = stuff[2]
this.underline = stuff[3]
}
var style_map = new Array();
/* The first index here corresponds to value 16 */
term256_colors = [ //247
"ffd7d7",
"d7afaf",
"af8787",
"875f5f",
"5f0000",
"870000",
"af0000",
"d70000",
"ff0000",
"ff5f5f",
"d75f5f",
"d78787",
"ff8787",
"ffafaf",
"ffaf87",
"ffaf5f",
"ffaf00",
"ff875f",
"ff8700",
"ff5f00",
"d75f00",
"af5f5f",
"af5f00",
"d78700",
"d7875f",
"af875f",
"af8700",
"875f00",
"d7af87",
"ffd7af",
"ffd787",
"ffd75f",
"d7af00",
"d7af5f",
"ffd700",
"ffff5f",
"ffff00",
"ffff87",
"ffffaf",
"ffffd7",
"d7ff00",
"afd75f",
"d7d700",
"d7d787",
"d7d7af",
"afaf87",
"87875f",
"5f5f00",
"878700",
"afaf00",
"afaf5f",
"d7d75f",
"d7ff5f",
"d7ff87",
"87ff00",
"afff00",
"afff5f",
"afd700",
"87d700",
"87af00",
"5f8700",
"87af5f",
"5faf00",
"afd787",
"d7ffd7",
"d7ffaf",
"afffaf",
"afff87",
"5fff00",
"5fd700",
"87d75f",
"5fd75f",
"87ff5f",
"5fff5f",
"87ff87",
"afd7af",
"87d787",
"87d7af",
"87af87",
"5f875f",
"5faf5f",
"005f00",
"008700",
"00af00",
"00d700",
"00ff00",
"00ff5f",
"5fff87",
"00ff87",
"87ffaf",
"afffd7",
"5fd787",
"00d75f",
"5faf87",
"00af5f",
"5fffaf",
"00ffaf",
"5fd7af",
"00d787",
"00875f",
"00af87",
"00d7af",
"5fffd7",
"87ffd7",
"00ffd7",
"d7ffff",
"afd7d7",
"87afaf",
"5f8787",
"5fafaf",
"87d7d7",
"5fd7d7",
"5fffff",
"00ffff",
"87ffff",
"afffff",
"00d7d7",
"00d7ff",
"5fd7ff",
"5fafd7",
"00afd7",
"00afff",
"0087af",
"00afaf",
"008787",
"005f5f",
"005f87",
"0087d7",
"0087ff",
"5fafff",
"87afff",
"5f87d7",
"5f87ff",
"005fd7",
"005fff",
"005faf",
"5f87af",
"87afd7",
"afd7ff",
"87d7ff",
"d7d7ff",
"afafd7",
"8787af",
"afafff",
"8787d7",
"8787ff",
"5f5fff",
"5f5fd7",
"5f5faf",
"5f5f87",
"00005f",
"000087",
"0000af",
"0000d7",
"0000ff",
"5f00ff",
"5f00d7",
"5f00af",
"5f0087",
"8700af",
"8700d7",
"8700ff",
"af00ff",
"af00d7",
"d700ff",
"d75fff",
"d787ff",
"ffafd7",
"ffafff",
"ffd7ff",
"d7afff",
"d7afd7",
"af87af",
"af87d7",
"af87ff",
"875fd7",
"875faf",
"875fff",
"af5fff",
"af5fd7",
"af5faf",
"d75fd7",
"d787d7",
"ff87ff",
"ff5fff",
"ff5fd7",
"ff00ff",
"ff00af",
"ff00d7",
"d700af",
"d700d7",
"af00af",
"870087",
"5f005f",
"87005f",
"af005f",
"af0087",
"d70087",
"d7005f",
"ff0087",
"ff005f",
"ff5f87",
"d75f87",
"d75faf",
"ff5faf",
"ff87af",
"ff87d7",
"d787af",
"af5f87",
"875f87",
"000000",
"080808",
"121212",
"1c1c1c",
"262626",
"303030",
"3a3a3a",
"444444",
"4e4e4e",
"585858",
"5f5f5f",
"626262",
"6c6c6c",
"767676",
"808080",
"878787",
"8a8a8a",
"949494",
"9e9e9e",
"a8a8a8",
"afafaf",
"b2b2b2",
"bcbcbc",
"c6c6c6",
"d0d0d0",
"d7d7d7",
"dadada",
"e4e4e4",
"eeeeee",
"ffffff",
]
var items_per_row = 15
var show_labels = 0
var COLOR_NORMAL = 'CCC'
/* Adds a new element to master */
function create_master_element(contents, color, font_size, click_handler) {
/* In the master list, ensure the color is visible against the dark background */
var master_color = color ? master_color_for_color(color) : COLOR_NORMAL
var style_str = 'color: #' + master_color + '; border-bottom: 1px solid #' + master_color + ' ;'
if (font_size.length > 0) {
style_str += 'font-size: ' + font_size + ';'
}
if (contents.length >= 20) {
style_str += 'letter-spacing:-2px;'
}
elem = $('<div/>', {
class: 'master_element',
id: 'master_' + contents,
click: function(){
click_handler(this)
}
}).append(
$("<span/>", {
class: 'master_element_text',
style: style_str,
text: contents,
})
)
elem.appendTo('#master')
return elem
}
/* Toggle the no_overflow class */
function toggle_overflow(who) {
$(who).toggleClass('no_overflow')
}
/* Creates a new row in the data table */
function create_data_table_element(contents_list) {
var row = $('<tr>', {
class: 'data_table_row'
})
for (idx = 0; idx < contents_list.length; idx++) {
/* If we have more than one, then align the first one right, subsequent ones left */
if (idx == 0 && contents_list.length > 1) {
cell = $('<td>', {
class: 'data_table_cell no_overflow',
style: 'text-align: right; padding-right: 30px;'
});
} else {
cell = $('<td>', {
class: 'data_table_cell no_overflow',
style: 'text-align: left',
onClick: 'toggle_overflow(this)'
});
}
text_list = contents_list[idx].split("\n")
for (j=0; j < text_list.length; j++) {
cell.append($('<p>', {
text: text_list[j]
}))
}
row.append(cell)
}
$('#data_table').append(row)
}
/* Put stuff in colorpicker_term256 */
function populate_colorpicker_term256() {
var idx
for (idx = 0; idx < term256_colors.length; idx += items_per_row) {
var row = $('<tr>', {
class: 'colorpicker_term256_row'
})
for (var subidx = 0; subidx < items_per_row && idx + subidx < term256_colors.length; subidx++) {
cell_style = 'background-color: #' + term256_colors[idx + subidx]
var cell = $('<td>', {
class: 'colorpicker_term256_cell',
style: cell_style,
id: 'color_' + term256_colors[idx + subidx],
text: show_labels ? String(subidx + idx + 223) : '',
onClick: 'picked_color_cell(this)'
})
/* For reasons I don't understand, this makes the selected cell border appear in Firefox */
cell.append($('<div>', {
style: 'width: 100%; height: 100%'
}))
row.append(cell)
}
$('#colorpicker_term256').append(row)
}
}
$(document).ready(function() {
populate_colorpicker_term256()
switch_tab('tab_colors')
})
</script>
</head>
<body>
<div id="ancestor">
<span style="font-size: 30pt">fish</span><p id="global_error" class="error_msg"></p>
<div id="parent">
<div id="tab_parent">
<div class="tab selected_tab" id="tab_colors" onClick="switch_tab('tab_colors')">colors</div>
<div class="tab" id="tab_functions" onClick="switch_tab('tab_functions')">functions</div>
<div class="tab" id="tab_variables" onClick="switch_tab('tab_variables')">variables</div>
<div class="tab" id="tab_history" onClick="switch_tab('tab_history')">history</div>
</div>
<div id="tab_contents">
<div id="master_detail_table">
<div id="master"></div>
<div id="detail">
<div id="detail_colorpicker">
<div class="colorpicker_target">
<div class="colorpicker_target_tab tab_first colorpicker_target_selected" id="foreground" onClick="picked_colorpicker_target(this)">Text</div><div class="colorpicker_target_tab tab_last" id="background" onClick="picked_colorpicker_target(this)">Background</div>
</div>
<table id="colorpicker_term256">
</table>
<div class="colorpicker_modifiers">
<div class="colorpicker_modifier_cell" id="modifier_underline" style="text-decoration: underline" onClick='picked_modifier(this)'>Underline</div>
</div>
</div>
<div id="detail_function"></div>
</div>
</div>
<table id="data_table">
<table>
<div class="footer">
</div>
</div>
</div>
</div>
</body></html>